Я хочу использовать List в качестве очереди. Это связано с тем, что List более гибок при получении/вставке данных.
Мой вопрос: когда я использую операции Linq (DistinctBy, Take), как показано ниже, получаю ли я элементы в том порядке, в котором они были добавлены в список?
private List<IMessage> _queue = new List<IMessage>();
// add many
_queue.Add(tagMessage);
toConsume = _queue
.Where(t => !_snLockList.Contains(t.Id))
.DistinctBy(t => t.Id)
.Take(freeTasks).ToList();
Если вы добавляете элементы только в конец списка (используя .Add() или .AddRange()), добавленные элементы (за исключением тех, которые были позже удалены) останутся в том порядке, в котором они были добавлены. Если вы вставляете какие-либо элементы по определенному индексу, используя .Insert() или .InsertRange(), они останется в том же положении относительно элементов до и после. Имейте в виду, что List<> реализован с использованием массива под обложками, поэтому операции вставки и удаления, отличные от конца списка, могут быть дорогостоящими, поскольку они включают в себя перемещение элементов. в массиве.
Без order by или skip LINQ будет использовать отдельные элементы, которых нет в списке _snLockList. Я не понимаю, почему бы вам просто не использовать Console/Debug.Writeline() и не протестировать несколько сценариев?
Я выполнил много многопоточных операций, и список работает как очередь. Просто хочу посмотреть, будет ли это поведение нарушено при стрессе или каких-либо особых случаях при использовании операторов Where, DistinctBy, Take.
@mamen да, очень интересно, но по DistinctBy нет однозначного вывода. Я согласен с порядком «найден первым», но не с непредсказуемым порядком.
Список не является потокобезопасным (!) - он не требует стресса или особых случаев, чтобы ваша реализация испарилась. Прежде чем беспокоиться о конкретных операциях LINQ, ознакомьтесь с потокобезопасными реализациями IList.
LINQ рассматривает все как IEnumerable<T> результаты будут зависеть от реализации соответствующего перечислителя. На практике это почти всегда приводит к выводу элементов в том же порядке, в котором они вводятся, если операция специально не требует переупорядочения. Тем не менее, если это специально не задокументировано, это всего лишь результат удобства, а не необходимости, и нет никакой гарантии, что это не изменится в будущем. Опять же, однако, это вряд ли когда-либо изменится на практике. Тем не менее, если вам конкретно нужен заказ, вам следует реализовать его самостоятельно.
Обратите внимание, что многие методы LINQ имеют перегрузки, которые принимают элемент и его индекс в качестве аргументов. Вы можете начать с вызова Select и создания анонимных объектов, включающих элемент и его индекс, а затем закончить OrderBy, который упорядочивает по индексу, а затем Select, который извлекает элемент.
На самом деле, последнее предложение, вероятно, не сработает. Индексы, предоставляемые LINQ, вероятно, просто следуют порядку перечисления, независимо от того, соответствует ли он порядку исходного списка или нет. Если все IEnumerable<T>, нет никакой гарантии, что существует какой-либо способ получить исходный индекс или даже если он есть, например. в Dictionary. Вы могли бы проверить5 это, создав собственный тип коллекции, который намеренно перечисляется не по порядку, но я не думаю, что буду тратить на это время.
@Patola This is because List is more flexible when getting/inserting data. угадай, что List и Queue используют для хранения: T[]. У них одинаковые ограничения на потоки. ConcurrentQueue и ConcurrentStack потокобезопасны и используют очень мало (если вообще используют) блокировок. Нет ConcurrentList
Кажется, это можно очень легко попробовать? У вас уже есть код и, предположительно, есть входные данные. Почему вы не запустили этот код самостоятельно, чтобы проверить, будет ли ответ «да» или «нет»?
Имя toConsume указывает на то, что вы, возможно, захотите удалить некоторые элементы из списка, а не просто выбрать некоторые элементы. По крайней мере, именно так обычно работают системы производитель-потребитель. Если вы хотите эффективно удалить несколько элементов из списка и контролировать порядок удаления элементов, вам может показаться этот вопрос интересным (отправная точка для пользовательской RemoveMany реализации).





Ответ: «Да, но…».
Да, все операции LINQ, которые перебирают коллекции с использованием шаблона «foreach, yield return», возвращают результаты в порядке IEnumerable базового объекта (ваших List<T>) (см. MS Doc - выход, также перейдите по ссылке в этой статье, чтобы iterators) - если/пока другая операция не изменит порядок (Sort()).
Но вы не даете достаточного понимания того, «что, как и почему» того, что вы делаете... (1) Списки можно использовать для реализации довольно эффективных (кольцевых) очередей («кольцевых буферов» - для которых вы, вероятно, будете придется кодировать итератор/ы). (2) Если вы собираетесь вставлять и удалять из середины очереди, то вы должны использовать (O(n), т.е. довольно дорогую) логику перемешивания вверх и вниз (за кулисами Insert(), RemoveAt()... и ваша очередь не является FIFO, то есть на самом деле это не очередь).
Вы рассматривали возможность использования PriorityQueue<T> или LinkedList<T>?
Я использую _queue.Add(tagMessage);, _queue.Insert(index, tagMessage); а затем описанная выше операция linq для выбора нескольких элементов, а затем я удаляю их _queue.RemoveAll(t => toConsume.Any(x => x.QueueId == t.QueueId));. Это операции, которые я использую. Я хочу, чтобы список сохранял порядок индекса. Это не строгая очередь. Все операции выполняются под блокировкой из-за многопоточного доступа.
Я вижу, что вопрос закрыт (дублирование в аспекте упорядочивания запросов LINQ). Если очередь может стать большой и/или важна производительность (и/или вы, как и я, ОКР в отношении дизайна ;-), то, судя по вашему описанию, я бы серьезно рассмотрел LinkedList<T> с политикой «добавляй в хвосте и сначала потребляй, доступный из голова/перед». Преимущество заключается в том, что операции вставки и удаления O(1) требуют (вероятно, гораздо меньших) затрат на некоторую фрагментацию памяти (управление памятью в .NET превосходно). (Возможно, также придется отказаться от некоторой аккуратности и краткости LINQ.)
Имеет ли название вопроса какое-либо отношение к тому, что задается внутри? По сути, вы спрашиваете о поведении операторов LINQ
Where,DistinctBy,TakeиToList, сохраняют ли они порядок последовательностиsourceили нет. Не имеет значения, является лиsourceсписком, очередью или какой-либо другой коллекцией.