В течение некоторого времени я структурировал свой код вокруг методов без побочных эффектов, чтобы использовать параллельный linq для ускорения работы. По пути я не раз натыкался на ленивую оценку, делающую что-то хуже, а не лучше, и я хотел бы знать, есть ли какие-либо инструменты для оптимизации параллельных запросов linq.
Я спрашиваю, потому что недавно я реорганизовал какой-то неловко параллельный код, изменив некоторые методы и нагромождая AsParallel
в определенных ключевых местах. Время работы сократилось с 2 минут до 45 секунд, но из монитора производительности стало ясно, что в некоторых местах все ядра на процессоре полностью не используются. После нескольких ложных запусков я заставил некоторые из запросов выполнить с помощью ToArray
, а время выполнения еще больше снизилось до 16 секунд. Было приятно сократить время выполнения кода, но оно также немного сбивало с толку, потому что было неясно, где в кодовых запросах необходимо принудительно с помощью ToArray
. Ожидание до последней минуты выполнения запроса не было оптимальной стратегией, но было не совсем ясно, в каких точках кода некоторые из подзапросов необходимо принудительно использовать, чтобы использовать все ядра ЦП.
Как я уже не знаю, как правильно перец ToArray
или другие методы, которые принудительно выполняют вычисления linq, чтобы получить максимальную загрузку процессора. Итак, есть ли общие рекомендации и инструменты для оптимизации параллельных запросов linq?
Здесь пример псевдокода:
var firstQuery = someDictionary.SelectMany(FirstTransformation);
var secondQuery = firstQuery.Select(SecondTransformation);
var thirdQuery = secondQuery.Select(ThirdTransformation).Where(SomeConditionCheck);
var finalQuery = thirdQuery.Select(FinalTransformation).Where(x => x != null);
FirstTransformation
, SecondTransformation
, ThirdTransformation
все связаны с ЦП и с точки зрения сложности они представляют собой несколько матричных умножений 3x3 и некоторые ветки if
. SomeConditionCheck
- это почти проверка null
. FinalTransformation
- это большая часть кода, требующая большей части кода, потому что она будет выполнять целую кучу пересечений линейных плоскостей и будет проверять локализацию многоугольника для этих пересечений, а затем извлечь пересечение, которое ближе всего к определенной точке на линии.
Я понятия не имею, почему места, где я положил AsParallel
, сократили время выполнения кода столько же, сколько и сделали. Теперь я достиг локального минимума с точки зрения времени выполнения, но я понятия не имею, почему. Мне просто не повезло, что я наткнулся на него. Если вам интересно, места, где положить AsParallel
- это первая и последняя строки. Ввод AsParallel
в другое место будет только увеличивать время выполнения, иногда на 20 секунд. В первой строке скрывается скрытый ToArray
.