2017-01-16 6 views
1

Я наткнулся на реализацию ContiguousChunkLazyEnumerator класс, который используется PLINQ (перемещение куска выполняется с помощью этого итератора). MoveNext метод использует поточный безопасный доступ к источнику IEnumerator (с использованием speficied lock), кроме того, он сохраняет результаты доступа к внутреннему буферу. Это краткое фрагмент кода:Выполнение перемещения раздела chunk в PLINQ

lock (m_sourceSyncLock) 
{ 
// Some .net stuff 
    try 
    { 
     for (; i < mutables.m_nextChunkMaxSize && m_source.MoveNext(); i++) 
     { 
     // Read the current entry into our buffer. 
     chunkBuffer[i] = m_source.Current; 
     } 
    } 
// Some .net stuff 
} 

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

ответ

2

Это связано с тем, что использование PLINQ оптимизирует параллельную обработку элементов, а не для параллельного перечисления элементов.

Тяжелый lock выполнен за кусок, поэтому несколько потоков будут уступать друг другу между кусками.

Это действительно сияет, когда у вас есть IEnumerable, которое быстро перечислить (как List<T>, например, в действительности, есть внутренние оптимизации для List<T>, поэтому не лучший пример), и хотят сделать несколько медленных вычисления работы над Результаты.

Этот код посвящен созданию секционированных данных, которые затем потребляются несколькими потоками. Несмотря на то, что он является потокобезопасным, он не должен быть о самом быстром параллельном перечислении. Он оптимизирован для локализации данных.

+0

Я не понимаю вашего ответа. Я не вижу параллельных вычислений элементов коллекции (производительность блокировок убивает). Простая заметка - список будет обрабатываться разделом диапазона, а не секцией chunk. – LmTinyToon

+0

Да, я упомянул оптимизацию 'List '. Я имею в виду, что этот код предназначен для создания секционированных данных, которые затем будут потребляться несколькими потоками. Несмотря на то, что он является потокобезопасным, он не должен быть о самом быстром параллельном перечислении. Он оптимизирован для локальности данных. – Stuart