Будет ли многопоточное приложение на самом деле быстрее однопоточного?

Все чисто теоретически, вопрос только что пришел в голову, и я не был полностью уверен, каков ответ:

Предположим, у вас есть приложение, которое рассчитывает 4 независимых расчета. (Абсолютно независимый, не имеет значения, в каком порядке вы их выполняете, и вам не нужен один для расчета другого). Также предположим, что эти вычисления длинные (минуты) и привязаны к процессору (не ожидая ввода-вывода)

1) Теперь, если у вас есть однопроцессорный компьютер, однопоточное приложение будет логически быстрее, чем (или то же самое, что) многопоточное приложение. Поскольку компьютер не может выполнять более одного действия одновременно с одним процессором, он "теряет" время на переключение контекста и тому подобное. Все идет нормально?

2) Если у вас 4-процессорный компьютер, 4 потока, скорее всего, будут быстрее для этого, чем один поток. Правильно? теперь ваш компьютер может выполнять 4 операции одновременно, поэтому логично разделить ваше приложение на 4 потока, и оно должно завершиться за время, которое занимает самый длинный из 4 вычислений. До сих пор хорошо?

3) А теперь фактическая часть, в которой я запутался - зачем мне когда-либо, чтобы мое приложение создавало больше потоков, чем число доступных процессоров (ну, собственно, ядер)? Я запрограммировал и видел приложения, которые создают десятки и сотни потоков, но на самом деле - идеальное число составляет около 8 для среднего компьютера?

PS Я уже читал это: Threading vs single thread, но не ответил тихо.

ура

4 ответа

Зачем мне когда-либо, чтобы мое приложение создавало больше потоков, чем число доступных процессоров (ну, собственно, ядер)?

Одна очень веская причина - если у вас есть потоки, которые ждут событий. Например, у вас может быть приложение производителя / потребителя, в котором производитель читает из некоторого потока данных, и эти данные поступают пакетами: несколько сотен (или тысяч) записей в пакете, после которых некоторое время ничего не происходит, а затем другое взрыв. Скажем, у вас есть 4-ядерный компьютер. Вы можете иметь один поток производителя, который считывает данные и помещает их в очередь, и три потока потребителя для обработки очереди.

Или вы можете иметь один поток производителя и четыре потока потребителя. Большую часть времени поток производителя простаивает, предоставляя вам четыре пользовательских потока для обработки элементов из очереди. Но когда элементы доступны в потоке данных, один из потоков потребителя заменяется в пользу производителя.

Это упрощенный пример, но в значительной степени похож на программы, которые у меня есть в производстве.

В более общем смысле, нет смысла создавать более непрерывно работающие (то есть связанные с ЦП) потоки, чем у вас есть процессорные блоки (ядра ЦП в целом, хотя наличие гиперпоточности немного запутывает воду). Если вы знаете, что ваши потоки не будут ожидать внешних событий, тогда n+1 темы, когда у вас есть только n ядра будут тратить время на переключение контекста потока. Обратите внимание, что это строго в контексте вашей программы. Если запущены другие приложения и службы ОС, потоки вашего приложения время от времени меняются местами, чтобы другие приложения и службы могли получать временные интервалы. Но предполагается, что, если вы запускаете программу, интенсивно использующую процессор, вы будете ограничивать другие приложения и службы, которые работают одновременно.

Лучше всего, конечно, настроить тест. На 4-ядерном компьютере протестируйте свое приложение с 1, 2, 3, 4, 5, ... потоками. Время, которое требуется для завершения с различным количеством потоков. Я думаю, вы обнаружите, что на 4-ядерном компьютере лучше всего будет 3 или 4; Скорее всего, 4, если нет других приложений или служб ОС, которые занимают много ЦП.

Одна из причин, по которой я мог бы придумать больше потоков, чем ядер, заключалась в том, что некоторым потокам нужно было взаимодействовать с другими сторонами... в ожидании ответа от сервера... для запроса чего-либо из базы данных. Это позволит ветке спать, пока не будет предоставлен ответ. таким образом, другие вычисления не должны были бы ждать. в 4cores->4thread поток будет ожидать ввода, что, возможно, заставит другой код ждать тоже

Добавление потоков в ваше приложение не связано исключительно с повышением производительности. Иногда вам нужно или нужно выполнять более одной задачи одновременно, потому что это наиболее логичный способ создания вашей программы.

Например, возможно, вы пишете игровой движок, если вы используете многопоточный подход, у вас может быть один поток для физики, один поток для графики, один поток для работы в сети, один поток для ввода данных пользователем, один поток для загрузки ресурсов. с диска и т. д.

Также Джеймс Бакстерс очень правдив. Иногда потоки ожидают на ресурсе и не могут работать дальше, пока не получат доступ к указанному ресурсу. При таком же количестве потоков, как у ядер, одно ядро ​​будет потрачено впустую.

Я думаю, вы предполагаете, что все программы связаны с процессором - помните, что некоторые из ваших потоков будут ожидать ввода / вывода (дисковый / сетевой / пользовательский трафик).

Другие вопросы по тегам