2010-03-08 3 views
3

Я пытаюсь понять, как параллелизм может работать с использованием PLINQ, учитывая задержку выполнения. Вот простой пример.PLINQ отложенное выполнение

string[] words = { "believe", "receipt", "relief", "field" }; 
bool result = words.AsParallel().Any(w => w.Contains("ei")); 

С помощью LINQ, я бы ожидать, что исполнение достичь «получение» значение и возвращает истину, без выполнения запроса для остальных значений.

Если мы сделаем это параллельно, оценка «облегчения» может начаться до того, как результат «получения» вернется. Но как только запрос знает, что «квитанция» приведет к истинному результату, будут ли текущие потоки немедленными?

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

ответ

4

К сожалению, другие потоки не будут «немедленно уступать».

Как только Any() найдет действительный элемент, планировщик PLINQ прекратит планирование новых потоков для проверки новых элементов. Любые существующие разделители также получат запрос на отмену, который запретит этим разделам звонить Any() на другой элемент.

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

На стороне записки:

PLINQ, в отличие от LINQ к объектам, на самом деле не использовать отложенное выполнение. Когда вы вызываете AsParallel() на IEnumerable<T>, генерируемый ParallelQuery<T> фактически начнет обрабатывать вашу процедуру параллельно. Отсроченное исполнение резко снизило бы эффективность PLINQ, так как было бы невозможно запланировать параллельно, не создавая рабочих разделителей и планируя заранее.


Edit:

Подумав об этом - если ваш лямбда-очень дорого, вы можете рассмотреть вопрос об использовании CancellationToken. Я подробно рассказал о how cancellation in PLINQ works. Как правило, вы просто используете токен и звоните ThrowIfCancellationRequested() - однако вы также можете использовать CancellationToken и проверить IsCancellationRequested, что позволило бы вам сделать ваш лямбда «выходным раньше», предоставляя вам способ остановить фоновую обработку раньше ...

+0

http://msdn.microsoft.com/en-us/library/dd997425(VS.100).aspx говорит, что принципы отложенного исполнения все еще находятся в игре с PLINQ ... можете ли вы немного уточнить, что вы имеете в виду в своем боковая точка? – tbischel

+0

@tbischel: Они делают, и они этого не делают ... Этот комментарий немного вводит в заблуждение. Разница в том, что в LINQ каждый элемент выполняется только по запросу (отложен). В PLINQ, как только вы делаете запрос FIRST, настраивается 'Partitioner ' ', который начинает планировать вашу работу для нескольких потоков. Окончательные накопленные результаты не возвращаются до запроса, но обработка выполняется до запроса элемента. (Если вы запрашиваете элемент 1 результатов, элементы 1,2,3 и 4 могут быть запланированы и начать «работать» сразу ...) –