PLINQ отложенное выполнение - PullRequest
3 голосов
/ 08 марта 2010

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

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

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

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

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

1 Ответ

4 голосов
/ 08 марта 2010

К сожалению, другие темы не будут "давать" сразу.

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

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

На примечании стороны:

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


Edit:

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

...