Ответ 1
Если ваш IEnumerable был действительно тем, у кого был указатель (например, вы могли бы сделать obj[1]
, чтобы получить элемент), вы можете сделать следующее
var rangePartitioner = Partitioner.Create(0, source.Length);
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
// Loop over each range element without a delegate invocation.
for (int i = range.Item1; i < range.Item2; i++)
{
var item = source[i]
//Do work on item
}
});
Однако, если он не может этого сделать, вы должны написать пользовательский разделитель, создав новый класс, полученный из System.Collections.Concurrent.Partitioner<TSource>
. Этот вопрос слишком широк, чтобы охватить SO-ответ, но вы можете взглянуть на это руководство по MSDN, чтобы начать работу.
ОБНОВЛЕНИЕ:. По сравнению с .NET 4.5 они добавили перегрузку Partitioner.Create
, которая не хранит данные, имеет тот же эффект создавая пользовательский разделитель с максимальным размером диапазона 1. При этом вы не получите ни одного потока, который имеет кучу работы в очереди, если ему не повезло с кучей медленных элементов в строке.
var partitoner = Partitioner.Create(source, EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitoner, item =>
{
//Do work
}