Как многопоточность ускоряет работу приложения (когда потоки не могут запускаться одновременно)?

Я изучаю многопоточность, но, прочитав несколько учебников, я немного смущен. Я не понимаю, как многопоточность может ускорить приложение.

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

Как и когда многопоточность ускоряет работу приложения, когда потоки не могут работать одновременно?

Ответ 1

Два способа, о которых я могу думать, первый из которых, вероятно, вы подразумеваете под "параллельной резьбой".

  • Если у вас несколько процессоров или ядер, они могут работать одновременно, если вы используете несколько потоков.
  • В случае с одним ядром, если ваш поток заканчивается в ожидании (синхронного) ввода-вывода, скажем, вы вызываете read(), чтобы читать 100 МБ с ленты, другой поток может быть запланирован и получить работу во время ожидания.

Ответ 2

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

Обязательная ссылка: http://en.wikipedia.org/wiki/Amdahl's_law

Кроме того, как сказал Марк Рэнсом, если ваше оборудование не может на самом деле сделать больше, чем 1 вещь сразу, то потоки фактически просто логически работают в одно и то же время (путем обмена), чем фактически работают в одно и то же время. Однако это может быть полезно в ситуациях с блокировкой ввода-вывода.

Ответ 3

потому что вам постоянно приходится ждать этих семафоров.

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

Даже без параллельной (многоядерной/многопроцессорной) обработки многопоточность может быть полезна, когда потоки блокируют ввод-вывод. Например, старые добрые программы CVSup использовали многопоточность в одноядерную эру, чтобы в полной мере использовать возможности дуплексной связи сетевых подключений. В то время как один поток ожидал, что данные поступят по ссылке, другой будет толкать данные другим способом. Из-за задержки в сети оба потока обязательно должны были тратить много времени на ожидание, в течение которых другие потоки могли бы выполнять полезную работу.

Ответ 4

Одним из наиболее важных применений многопоточности является программирование графического интерфейса. Если у вас был только один поток, что происходит, когда вы нажимаете кнопку? Вам нужно будет подождать, пока какое действие не будет выполнено, до того, как управление вернется в графический интерфейс. Положить это в контекст. Если ваш браузер работает только в одном потоке, и вы хотите скачать, то, например, Linux ISO, весь браузер будет непригодным для использования во время загрузки, поскольку один поток будет рассмотрен с загрузкой и не будет доступный для реагирования на действия пользователя. Вы даже не можете отменить загрузку.

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

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

Кроме того, семафоры не всегда необходимы. Это зависит от того, что вы делаете. Если у вас есть несколько потоков, потребляющих задания из одной рабочей очереди, вы хотите убедиться, что задание удалено из очереди, прежде чем другой поток сможет запросить задание, чтобы вы не назначали одну и ту же работу для 2 потоков. В этом случае вы используете семафоры, чтобы сделать вашу рабочую очередь "потокобезопасной". С другой стороны, hootsuite или один из этих других клиентов настольных компьютеров в социальных сетях (не знаю, делают ли они) запускают поток для каждой платформы, к которой вы подключены, чтобы вы могли одновременно получать обновления с нескольких платформ.

Ответ 5

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

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

Еще одно использование потоков - сохранить отзывчивость, представить сценарий, когда вам нужно выполнять тяжелые операции ввода-вывода, такие как чтение с устройства, выборка данных из сети и т.д., если вы выполняете эти операции в основном потоке, ваш ui будет заблокирован во время работы ввода-вывода. Вы можете избежать блокировки ui, выполнив операции ввода-вывода в разных потоках. Возможно, это означало "ускорение приложения".

Ответ 6

Не все происходит на процессоре. Представьте себе компьютер, который не имеет потоков. Этот компьютер будет тратить очень много времени:

  • ожидание ответа клавиатуры
  • ожидание ответа мыши
  • ожидание завершения жесткого диска
  • ожидание появления сетевого пакета из какого-либо адресата

и т.д. Фактически, такой компьютер не сможет ничего сделать с процессором, если система спроектирована как минимально интерактивная.

То же самое, в меньшей степени, относится к ОДНОМУ процессу, то есть к вашему приложению.

EDIT:

До "хороших" ядер, которые работают на "хороших" процессорах, таких как 286, и оттуда OS-es (или примитивные OS-es) имитировали многопоточность, обрабатывая прерывания. Даже ZX Spectrum имел прерывания для обработки клавиатуры, например (если я правильно помню).

Ответ 7

Удаление "параллельной потоковой передачи" из концепции многопоточности делает ее бессмысленной - если вы не разрешаете потокам выполнять одновременно, то все, что у вас есть, - это один поток обработки, который тратит много времени на перескок в планировщике ОС.

То, что потоки могут работать параллельно, - это все усиление производительности. Вы должны оптимизировать свой код, чтобы семафоры редко использовались, если когда-либо - вы правы, что они дороги. Общий подход - объединение потоков и циклов событий; предположим, что у вас было 2000 объектов, которые вы хотели бы изменить, вы бы вложили 2000 связанных задач в пул потоков. Пул потоков будет обеспечивать, чтобы отдельные действия выполнялись на таких потоках, которые становятся доступными, когда они становятся доступными. Если он затем сможет отправить событие в определенный цикл событий, когда работа выполнена, в вашем коде нет явных семафоров.

Ответ 8

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

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

Ответ 9

Думайте о потоках как о "вещах, происходящих одновременно".

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

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

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