PLINQ отложенное выполнение

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

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

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

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

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


person tbischel    schedule 08.03.2010    source источник


Ответы (1)


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

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

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

На заметку:

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


Редактировать:

Подумав об этом - если ваша лямбда ОЧЕНЬ дорогая, вы можете рассмотреть возможность использования Токен отмены. Я подробно писал в блоге о как работает отмена в PLINQ. Как правило, вы просто используете токен и вызываете ThrowIfCancellationRequested() — однако вы также можете использовать CancellationToken и проверить IsCancellationRequested, что позволит вам сделать лямбда-выход "ранее", предоставляя вам способ остановить фоновую обработку раньше...

person Reed Copsey    schedule 08.03.2010