Как отмечает @Baile в комментариях, это сильно зависит от приложения, системы, среды.
И поэтому я не собираюсь придерживаться жесткого подхода, когда упоминается ровно 1 поток для каждого ядра. (или 2 потока / ядро в случае Hyperthreading)
Как опытный программист с разделяемой памятью, из своего опыта я видел, что оптимальное число потоков (для 4-ядерных компьютеров) может варьироваться от 1 до 64 +.
Теперь я перечислю ситуации, которые могут вызвать этот диапазон:
Оптимальные потоки <количество ядер </strong>
В определенных задачах с очень мелкозернистой параллелью (таких как небольшие БПФ) накладные расходы на многопоточность являются доминирующим фактором производительности. В некоторых случаях не стоит распараллеливать вообще. В некоторых случаях вы получаете ускорение с 2 потоками, но при обратном масштабировании на 4 потока.
Другая проблема - конфликт ресурсов. Даже если у вас есть задача с высокой степенью распараллеливания, которую можно легко разделить на 4 ядра / потоки, вы можете оказаться в узком месте из-за пропускной способности памяти и эффектов кэша. Очень часто вы обнаружите, что 2 потока будут такими же быстрыми, как 4 потока. (как часто бывает с очень большими БПФ)
Оптимальные потоки = количество ядер
Это оптимальный случай. Не нужно объяснять здесь - один поток на ядро. Большинство смущающих параллельных приложений, которые не связаны с памятью или вводом-выводом, подходят именно здесь.
Оптимальные потоки> Количество ядер
Вот тут становится интересно ... очень интересно. Вы слышали о дисбалансе нагрузки? Как насчет чрезмерного разложения и кражи работы?
Многие распараллеливаемые приложения нерегулярны - это означает, что задачи не разбиваются на подзадачи одинакового размера. Так что, если вы можете разделить большую задачу на 4 неравных размера, назначьте их на 4 потока и запустите на 4 ядрах ... результат? Плохая параллельная производительность, потому что 1 поток получил в 10 раз больше работы, чем другие потоки.
Распространенным решением здесь является чрезмерное разложение задачи на множество подзадач. Вы можете создавать потоки для каждого из них (так что теперь вы получаете threads >> cores ). Или вы можете использовать какой-нибудь планировщик задач с фиксированным числом потоков. Не все задачи подходят для обоих, поэтому довольно часто подход чрезмерного разбиения задачи на 8 или 16 потоков для 4-ядерного компьютера дает оптимальные результаты.
Хотя порождение большего количества потоков может привести к лучшему распределению нагрузки, накладные расходы возрастают. Так что обычно где-то есть оптимальная точка. Я видел до 64 потоков на 4 ядрах. Но, как уже упоминалось, это сильно зависит от приложения. И тебе нужно поэкспериментировать.
РЕДАКТИРОВАТЬ: Расширение ответа для более прямого ответа на вопрос ...
Сколько стоит переключение контекста? Время для хранения и восстановления
Регистры процессора для другого контекста?
Это очень зависит от окружающей среды - и его довольно сложно измерить напрямую.
Краткий ответ: Очень дорого Это может быть хорошим чтением.
А как насчет кешей, конвейеров и различных вещей с предсказанием кода внутри?
ЦПУ? Можем ли мы сказать, что каждый раз, когда мы меняем контекст, мы повреждаем кэши,
конвейеры и некоторые средства декодирования кода в CPU?
Краткий ответ: Да Когда вы переключаете контекст, вы, вероятно, очищаете свой конвейер и путаете все предикторы. То же самое с кешами. Новый поток, скорее всего, заменит кеш новыми данными.
Хотя есть одна загвоздка. В некоторых приложениях, где потоки совместно используют одни и те же данные, возможно, что один поток потенциально может «подогреть» кэш для другого входящего потока или другого потока в другом ядре, совместно использующих тот же кэш. (Хотя это случалось редко, я уже видел это раньше на одной из моих машин NUMA - суперлинейное ускорение: 17,6x на 16 ядер!?!?!)
То есть больше потоков, выполняющихся на одном ядре, меньше работы, которую они могут выполнять вместе, по сравнению с их последовательным выполнением?
Зависит, зависит ... Помимо гиперпоточности, определенно будут накладные расходы.Но я читал статью, в которой кто-то использовал вторую ветку для предварительной выборки основной ветки ... Да, это безумие ...