Это классическая ошибка: думать: «Я проведу простой тест, чтобы сравнить производительность этого однопоточного кода с этим многопоточным кодом».
A простой тест - это худший вид теста, который вы можете запустить для измерения многопоточной производительности.
Как правило, распараллеливание некоторых операций дает выигрыш в производительности , когдашаги, которые вы распараллеливаете, требуют значительной работы .Когда шаги просты - как, например, быстро * - накладные расходы на распараллеливание вашей работы в конечном итоге сводят на нет минимальный прирост производительности, который вы могли бы получить в противном случае.
Рассмотрите эту аналогию.
Вы строите здание.Если у вас есть один рабочий, он должен класть кирпичи один за другим, пока он не построит одну стену, затем сделать то же самое для следующей стены и так далее, пока все стены не будут построены и соединены.Это медленная и кропотливая задача, которая может выиграть от распараллеливания.
Правильный способ сделать это - распараллелить стенное здание - нанять, скажем,Еще 3 рабочих, и пусть каждый рабочий строит свою собственную стену, так что 4 стены могут быть построены одновременно.Время, необходимое, чтобы найти 3 дополнительных работников и назначить им их задачи, незначительно по сравнению с экономией, которую вы получите, подняв 4 стены в количестве времени, которое раньше требовалось для строительства 1.
неправильный способ сделать это - распараллелить укладку кирпича - нанять еще около тысячи рабочих и назначить каждого работника за один кирпич за раз.Вы можете подумать: «Если один рабочий может укладывать 2 кирпича в минуту, то тысяча рабочих сможет укладывать 2000 кирпичей в минуту, поэтому я выполню эту работу в кратчайшие сроки!»Но реальность такова, что, распараллеливая вашу рабочую нагрузку на таком микроскопическом уровне, вы тратите огромное количество энергии, собирая и координируя всех своих работников, назначая им задачи («положите этот кирпичик прямо здесь»), следя за тем, чтобы никто неработа мешает кому-либо еще и т. д.
Итак, мораль этой аналогии такова: в общем, используйте распараллеливание, чтобы разделить существенные единицы работы (например, стены), но оставьте незначительные единицы (например, кирпичи), которые будут обрабатываться обычным последовательным образом.
* По этой причине вы действительно можете сделать довольно хорошее приближение к приросту производительностираспараллеливания в более трудоемком контексте, взяв любой быстро исполняемый код и добавив в его конец Thread.Sleep(100)
(или другое случайное число).Внезапно последовательное выполнение этого кода будет замедлено на 100 мс за итерацию, в то время как параллельное выполнение будет значительно замедлено.