Улучшение времени выполнения из приложения, выполненного с многопоточностью, ограничено количеством физических ядер?
Я проводил тестирование с многопоточностью на виртуальной машине Linux, и я реализовал тест с 10 потоками (в этом приложении каждая инструкция будет выполняться в 10 раз больше, чем в однопоточном сценарии), и я настраивал число "физических ядер" из настроек виртуальной машины и в случае одного потока я получаю в среднем 3 с независимо от количества физических ядер, если число ядер установлено на 1, и я запускаю многопоточную версию, время выполнения будет 30 с. Если я запускаю его с 2 ядрами, я получаю 15 с, а с 8 ядрами (максимальное число, которое я могу установить) я получаю 6 с, я получаю эту зависимость из-за того, что я выполняю 10 раз каждую инструкцию или всегда так?
1 ответ
Если у вас N потоков, работающих на N ядрах, и если все они выполняют чистые вычисления (т. Е. Не ожидают каких-либо устройств ввода-вывода), и если они все полностью независимы друг от друга, то они должны иметь возможность выполнять N В один и тот же промежуток времени можно выполнить в разы больше работы, чем может выполнять один поток.
Но это если они полностью независимы. Это трудно достичь. Например, если каждый из потоков не может выполнять всю свою работу в своем независимом кеше (например, в кеше L1), то они будут конкурировать друг с другом за доступ к основной памяти. Иногда им придется ждать друг друга, потому что только одно ядро может получить доступ к основной памяти в любой момент. Таким образом, если потоки должны использовать память, то ускорение будет несколько меньше, чем в N раз.
Если потокам необходимо совместно использовать данные в основной памяти, это ухудшается, потому что тогда им нужно будет использовать взаимные блокировки исключения. Один поток может держать блокировку заблокированной, пока он выполняет десятки инструкций, и любой другой поток, который хочет такую же блокировку, должен будет ждать, пока она не будет завершена.
Если потоки должны синхронизироваться друг с другом / общаться друг с другом, то это еще хуже, потому что, если их рабочая нагрузка не будет тщательно сбалансирована, поток с меньшим количеством работы может тратить много времени в ожидании сигналов от потоков, у которых больше работы сделать.
Для новичка в программировании не является чем-то необычным придумать многопоточную версию однопоточного алгоритма и выяснить, что многопоточная версия на самом деле медленнее однопоточной.
Есть некоторые алгоритмы, для которых даже опытный программист не может ускорить процесс, добавляя в него больше потоков.