Подтвердить что ты не робот

ConcurrentBag - добавить несколько элементов?

Есть ли способ добавить несколько элементов в ConcurrentBag одновременно, а не по одному за раз? Я не вижу метод AddRange() на ConcurrentBag, но есть Concat(). Однако это не работает для меня:

ConcurrentBag<T> objectList = new ConcurrentBag<T>();

timeChunks.ForEach(timeChunk =>
{
    List<T> newList = Foo.SomeMethod<T>(x => x.SomeReadTime > timeChunk.StartTime);
    objectList.Concat<T>(newList);
});

Этот код использовался в Parallel.ForEach(), но я изменил его на выше, чтобы я мог устранить его. У переменной newList действительно есть объекты, но после объекта objectList.Concat < > line, objectList всегда имеет в нем 0 объектов. Неужели Concat < > не работает таким образом? Нужно ли добавлять элементы в ConcurrentBag по одному за раз с помощью метода Add()?

4b9b3361

Ответ 1

Да:)

Concat является, возможно, одним из расширений Enumerable. Он ничего не добавляет к ConcurrentBag, он просто возвращает какой-то фанковый объект, содержащий оригинальную сумку, и все, что вы там пытались добавить.

Помните, что результат Concat больше не является ConcurrentBag, поэтому вы не захотите его использовать. Это часть общей структуры LINQ, что позволяет сочетать неизменные последовательности. Разумеется, эта структура не пытается расширить параллельные свойства операндов до результата, поэтому результирующий объект не будет так хорошо подходить для многопоточного доступа.

(В принципе, Concat применяется к ConcurrentBag, потому что он предоставляет интерфейс IEnumerable<T>.)

Ответ 2

Concat - это метод расширения, предоставляемый LINQ. Это неизменная операция, которая возвращает еще один IEnumerable, который может перечислять исходную коллекцию, за которой сразу следует указанная коллекция. Это никоим образом не изменяет исходную коллекцию.

Вам нужно будет добавлять свои элементы в ConcurrentBag по одному за раз.

Ответ 3

(Я знаю, что это старый пост, подумал, что я кое-что добавлю).

Как и другие говорили: да, вам нужно добавить их по одному. В моем случае я добавил небольшой метод расширения, чтобы сделать вещи чище, но под капотом он делает то же самое:

    public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)
    {
        foreach (var element in toAdd)
        {
            @this.Add(element);
        }
    }

И затем:

    ConcurrentBag<int> ccBag = new ConcurrentBag<int>();
    var listOfThings = new List<int>() { 1, 2, 4, 5, 6, 7, 8, 9 };
    ccBag.AddRange(listOfThings);

Я также рассмотрел возможность использования AsParallel для добавления в метод расширения, но после запуска некоторых тестов при добавлении списка строк разных размеров, было намного медленнее использовать AsParallel (как показано здесь), в отличие от традиционного для цикла.

    public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)
    {
        toAdd.AsParallel().ForAll(t => @this.Add(t));
    }

Ответ 4

Я столкнулся с аналогичной проблемой, пытаясь обрабатывать более мелкие фрагменты данных параллельно, потому что один большой фрагмент синхронизировал веб-службу, которую я использовал для доступа к моим данным на отправляющей стороне, но я не хотел, чтобы что-то выполнялось медленнее обрабатывая каждый блок последовательно. Обработка записи данных по записи была еще медленнее - поскольку служба, которую я вызывал, могла обрабатывать массовые запросы, было бы лучше отправить как можно больше времени без выключения времени.

Как сказал Влад, совмещение параллельного мешка с типом объекта не возвращает параллельный пакет, поэтому concat не будет работать! (Мне потребовалось некоторое время, чтобы понять, что я не мог этого сделать.)

Попробуйте это вместо этого: создайте List<T>, а затем создайте ConcurrentBag<List<T>>. На каждой параллельной итерации он будет добавлять новый список в параллельный пакет. Когда выполняется параллельный цикл, проведите через теги ConcurrentBag и concat (или объединение, если вы хотите устранить возможные дубликаты) до первого List<T>, который вы создали, чтобы "сгладить" все в один список.