2010-04-22 3 views
4

В C#,Нерестовые рабочие потоки

Как бы один идти о нерест несколько потоков, а затем последовательно добавляя результаты в список, прежде чем вернуться весь результирующий набор?

Каковы некоторые лучшие практики?

Я до сих пор использую ManualResetEvent, чтобы сигнализировать, когда последний элемент обработан потоком.

Но когда он вернётся, мне нужно, чтобы они консолидировали результирующие множества в последовательном порядке, чтобы мы не попадали в конфликтные проблемы с списком возвращаемых значений (итоговые результаты).

ответ

1

Если вы знаете окончательный заказ до того, как вы создадите потоки (что подразумевается «последовательно»), вы можете передать индекс в каждый поток и записать его результаты в этот «слот» в массиве. Таким образом, когда все потоки завершили обработку (в любом порядке), результаты будут уже упорядочены правильно, избегая необходимости сортировки после обработки.

+1

Вы по-прежнему будете сталкиваться с конфликтными проблемами, получая ссылку на массив для слота. –

+0

@LB - нет конкуренции, если каждый поток имеет выделенный слот. Сам массив (в отличие от элементов, которые он ссылается) создается до того, как потоки запускаются и уничтожаются впоследствии, и неизменен во время обработки. Элементы создаются потоками, добавляются в массив, а затем используются (после завершения обработки) по «главному» потоку, так что снова нет споров. Очевидно, что в .net 4 есть более эффективные способы ... но OP указывает .net 3.5 –

1

Параллельная библиотека задач, которая теперь является частью Reactive Extensions for .NET Framework, делает такие вещи такими же тривиальными. Существует набор конструкций Parallel для распараллеливания кода и набор потокобезопасных Concurrent{Container}s, которые вы можете использовать с ними.

Вот пример квадратичной группировки чисел, используя Parallel.For и ConcurrentBag, чтобы сохранить результаты.

The ConcurrentBag является регулярным IEnumerable, как вы можете видеть, я использую регулярно, не параллельно foreach для распечатки результатов в конце.

Примечание. Все эти материалы на самом деле являются стандартными в .NET 4.0, вам просто нужно Rx, если вы хотите его для .NET 3.5.

+1

Как раз и предложить TPL, но я бы сказал, что теперь он является частью .NET framework НЕ расширения ** Rx **, однако он был частью расширений Parallel ** FX **;) – ntziolis

+1

@ntziolis: Если вы хотите его на 3,5, вам нужны расширения Rx. Он включает в себя backport TPL и PLINQ. –

+0

Слишком плохо Я не могу использовать RX. –

1

Если вы используете .Net 4, вы можете, например, использовать класс Task. Вот пример слияния Список

Task<List<string>> task1 = new Task<List<string>>(SomeFunction); 
Task<List<string>> task2 = new Task<List<string>>(SomeFunction); 
task1.Start(); 
task2.Start(); 

var taskList = new List<Task<List<string>>> {task1, task2}; 

Task.WaitAll(taskList.ToArray()); 

List<string> res = new List<string>(); 
foreach (Task<List<string>> t in taskList) 
{ 
    res.AddRange(t.Result); 
} 

и ваша функция

List<string> SomeFunction() 
{ 
    return new List<string>{"1","2"}; 
} 
0

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

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