5

У меня есть List<byte[]>, и мне нравится десериализовать каждого byte[] в Foo. Список упорядочен, и мне нравится писать параллельный цикл, в котором полученный List<Foo> содержит все Foo в том же порядке, что и исходный byte[]. Список значительно большой, чтобы сделать параллельную работу стоящей. Есть ли встроенный способ сделать это?Parallel.ForEach при сохранении порядка

Если нет, любые идеи о том, как добиться ускорения при запуске всего этого синхронно?

Благодаря

+0

сообщения некоторых примеры код, пожалуйста, и для записей делают вещи параллельно обязательно не делают быстрее и эффективнее ... Удивление если Parallel.For решит вашу проблему. – adt

+3

Это дубликат из этого: http://stackoverflow.com/questions/3639768/parallel-foreach-ordered-execution Так, чтобы ответить, вы можете использовать PLINQ (AsOrdered, AsParallel), чтобы получить работу. – Kadelka

+0

Лучше иметь параллельный эквивалент 'Select' или' Map' для сохранения порядка ввода. – leppie

ответ

4

Из информации вы» я понял, вы хотите иметь выходной массив Foo с размером, равным входному массиву байтов? Это верно?

Если да, то операция проста. Не беспокойтесь о блокировке или синхронизированных конструкциях, это приведет к разрушению всей скорости, которую дает вам распараллеливание.

Вместо этого, если вы подчиняются этому простому правилу любой алгоритм может быть распараллелены без блокировки или синхронизации:

Для каждого входного элемента Х [я] обработан, вы можете считывать из любого входного элемента X [J], но только запись в выходной элемент Y [I]

enter image description here

Посмотрите Scatter/Gather, этот тип операции называется собрать как только один выходной элемент записывается.

Если вы можете использовать приведенный выше принцип, тогда вы хотите создать свой выходной массив Foo [] спереди и использовать Parallel.For not ForEach на входном массиве.

Э.Г.

 List<byte[]> inputArray = new List<byte[]>(); 
     int[] outputArray = new int[inputArray.Count]; 

     var waitHandle = new ManualResetEvent(false); 
     int counter = 0; 

     Parallel.For(0, inputArray.Count, index => 
      { 
       // Pass index to for loop, do long running operation 
       // on input items 
       // writing to only a single output item 
       outputArray[index] = DoOperation(inputArray[index]); 

       if(Interlocked.Increment(ref counter) == inputArray.Count -1) 
       { 
        waitHandle.Set(); 
       } 
      }); 

     waitHandler.WaitOne(); 

     // Optional conversion back to list if you wanted this 
     var outputList = outputArray.ToList(); 
+0

Отмечен ваш ответ в качестве желаемого решения, хотя в итоге я пошел с помощью специального IPropagatorBlock и TPLDataflow через справку svick. Хотя оба вопроса и поток данных кажутся двумя совершенно разными концепциями на поверхности, параллельная обработка блоков данных внутри IPropagatorBlock значительно превосходила любой цикл Parallel.For в отношении моей конкретной проблемы. Я обнаружил, что накладные расходы на синхронизацию уведомления об отображении и завершении очень дороги и что TPL Dataflow нацелен на такие сценарии, как мой. Но это никоим образом не снижает ваше решение по моему конкретному вопросу ... –

+0

... в который не входит вопрос о синхронизации и завершении уведомления. Речь идет о Parallel.Foreach, сохраняя приказ, и ваше предлагаемое решение соответствует законопроекту. Большое спасибо. –

+0

Хорошая точка! Задача параллельной библиотеки - превосходное решение. Однако я удивлен, что это превзошло все ожидания. Может быть, его дросселирование задачи для выполнения более чем одной сериализации на поток? Для вышесказанного вы можете включить полное уведомление с помощью целочисленного счетчика и 'Interlocked.Increment (ref counter)', чтобы проверить, были ли обработаны все элементы. Затем установите waithandle для продолжения. –

2

Вы можете использовать словарь THREADSAFE с помощью ключа индекса ИНТ для хранения reult от обув так что в конце концов вы будете иметь все в распоряжение заказчика данных в словаре

+0

Спасибо, я знаю об этом, но звучит усложненно. Мне в основном нужна еще одна полная процедура, чтобы подождать следующего входящего Foo в следующем порядке, проверить синхронизацию и добавить элементы в правильном порядке в результирующий список. Похоже, что немного накладных расходов, которые могут победить целое понятие параллельной работы. –

Смежные вопросы