Что может сделать несколько потоков, чего не может один поток? [закрыто]

100

Хотя потоки могут ускорить выполнение кода, нужны ли они на самом деле? Может ли каждый фрагмент кода быть выполнен с использованием одного потока, или существует что-то, что может быть достигнуто только с использованием нескольких потоков?

Злые птицы
источник
29
Основываясь на некоторых ответах, уже размещенных здесь, я думаю, что некоторые пояснения в порядке. Цель многопоточности - позволить компьютерам одновременно выполнять более одной задачи. Если это сделать с помощью компьютера с одним ядром, вы не увидите никакого общего ускорения. То, что вы увидите, разблокируется; в однопоточной программе пользовательский интерфейс блокируется во время выполнения вычислений. В многопоточной программе пользовательский интерфейс может все еще использоваться, пока вычисления происходят в фоновом режиме.
Роберт Харви
11
Конечно, если у вас есть несколько процессорных ядер на вашем компьютере (что сегодня является обычным явлением), ваша программа может использовать потоки, чтобы использовать дополнительные ядра для выполнения вашей обработки, и вы увидите ускорение, поскольку вы тратите больше лошадиных сил на ваша вычислительная проблема. Если вы вообще не используете потоки, ваша программа будет использовать только одно ядро ​​процессора, что хорошо, если это все, что вам нужно.
Роберт Харви
14
Однопоточная программа не может заблокировать ресурсы, как многопоточная программа.
zzzzBov
3
Ответ: запустить на двух ядрах
Даниэль Литтл
6
Ответ: вызвать тупик.
Работа

Ответы:

111

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

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

Комплекс ответ ... более сложный! Причина, по которой многопоточные программы часто могут быть более эффективными, чем линейные, связана с аппаратной «проблемой». Процессор может выполнять вычисления быстрее, чем ввод-вывод памяти и жесткого диска. Так, например, инструкция «add» выполняется намного быстрее, чем «fetch». Кэши и извлечение инструкций специальной программы (не уверенный в точном значении здесь) могут до некоторой степени бороться с этим, но проблема скорости остается.

Потоки - это способ борьбы с этим несоответствием, используя ЦП для команд, связанных с ЦП, пока выполняются инструкции ввода-вывода. Типичный план выполнения потока, вероятно, будет следующим: выборка данных, обработка данных, запись данных. Предположим, что выборка и запись занимают 3 цикла, а обработка - один для наглядности. Вы видите, что когда компьютер читает или пишет, он ничего не делает по 2 цикла каждый? Очевидно, это лениво, и нам нужно взломать наш оптимистический кнут!

Мы можем переписать процесс, используя многопоточность, чтобы использовать это потерянное время:

  1. # 1 выборка
  2. нет операции
  3. # 2 выборки
  4. # 1 сделано, обработайте его
  5. написать # 1
  6. # 1 выборка
  7. # 2 сделано, обработайте его
  8. написать № 2
  9. выборка № 2

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

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

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

В случае нескольких ядер потоки предоставляют метод разделения работы между двумя ядрами. Выше все еще относится к каждому отдельному ядру, хотя; Программа, которая работает с максимальной эффективностью с двумя потоками на одном ядре, скорее всего будет работать с максимальной эффективностью с примерно четырьмя потоками на двух ядрах. (Эффективность здесь измеряется минимальным выполнением команды NOP.)

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

TL; DR: потоки могут разделяться, чтобы позволить компьютеру обрабатывать несколько задач асинхронно. Это позволяет компьютеру работать с максимальной эффективностью, используя все доступное время обработки, а не блокируя, когда процесс ожидает ресурс.

Michael K
источник
17
Отличный ответ. Я просто хотел пояснить, что после определенного момента добавление большего количества потоков может на самом деле замедлить работу программы , потому что используется все ранее «потраченное впустую» время, и теперь вы только добавляете дополнительное переключение контекста и накладные расходы на синхронизацию.
Карл Билефельдт
8
+1 за описание того, как потоки помогают в обработке блокировки ввода-вывода. Другое использование потоков состоит в том, чтобы позволить пользовательскому интерфейсу продолжать обрабатывать пользовательские действия (движение мыши, индикаторы выполнения, нажатия клавиш), поэтому пользовательское восприятие состоит в том, что программа не «зависла».
JQA
3
Еще одно дополнение: строго говоря, потоки не добавляют выразительности большинству языков; Вы могли бы, если бы вам было абсолютно необходимо, реализовать все мультиплексирование самостоятельно и получить те же результаты. Однако на практике это будет означать переопределение всей вашей библиотеки потоков - точно так же, как рекурсия не является строго необходимой, но ее можно эмулировать, написав собственный стек вызовов.
Килиан Фот
9
@james: я бы классифицировал обработку пользовательского интерфейса как еще одну форму ввода / вывода. Возможно, самое худшее, так как пользователи имеют тенденцию быть медлительными и нелинейными. :)
TMN
7
В этом вопросе есть молчаливое предположение о том, что компьютер является одноядерным или центральным процессором. Мои часы имеют два ядра, я сомневаюсь, что предположение справедливо на любых современных машинах.
Blueberryfields
37

Что может сделать несколько потоков, чего не может один поток?

Ничего.

Простой контрольный эскиз:

  • [Гипотеза Чёрча-Тьюринга] ⇒ Все, что можно вычислить, можно вычислить с помощью универсальной машины Тьюринга.
  • Универсальная машина Тьюринга однопоточная.
  • Следовательно, все, что можно вычислить, может быть вычислено одним потоком.

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

Итак, более интересным вопросом будет: «Может ли добавление только многопоточности к языку, не являющемуся полным по Тьюрингу, сделать его полным по Тьюрингу?» И я верю, ответ «Да».

Давайте возьмем тотальные функциональные языки. [Для тех, кто не знаком: так же, как функциональное программирование - это программирование с использованием функций, общее функциональное программирование - это программирование с использованием общих функций.]

Тотальные функциональные языки, очевидно, не являются полными по Тьюрингу: вы не можете написать бесконечный цикл в TFPL (на самом деле, это почти то же самое, что определение «всего»), но вы можете в машине Тьюринга, так что, по крайней мере, существует одна программа, которая не может быть записано в TFPL, но может быть в UTM, поэтому TFPL менее мощны в вычислительном отношении, чем UTM.

Однако, как только вы добавляете многопоточность в TFPL, вы получаете бесконечные циклы: просто выполняйте каждую итерацию цикла в новом потоке. Каждый отдельный поток всегда возвращает результат, следовательно, это Total, но каждый поток также порождает новый поток, который выполняет следующую итерацию, до бесконечности.

Я думаю, что этот язык будет полным по Тьюрингу.

По крайней мере, он отвечает на оригинальный вопрос:

Что может сделать несколько потоков, чего не может один поток?

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

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

Йорг Миттаг
источник
13
Так как вы привели «доказательство», я не могу помешать себе «ну, на самом деле ...» вас. Я думаю, что вы злоупотребляете понятием вычислимости. Доказательство - милая вещь, и я понимаю вашу точку зрения, но на самом деле это не на должном уровне абстракции. Неспособность что-либо делать - это не то же самое, что невозможность вычислять , например, вы не можете использовать свое доказательство, чтобы сказать, потому что машина Тьюринга может вычислить «каждую вычисляемую функцию», она может сделать это за 3 секунды. Строго говоря, однопоточный компьютер без прерываний не может получить доступ к вводу-выводу, в то время как его процессор занят выполнением вычислений.
xmm0
1
И ни один настоящий компьютер не является машиной Тьюринга.
Дженс
1
@ColeJohnson: тупик - это деталь реализации. Видимый вывод «не останавливается», что легко выполнимо с помощью одного потока.
Хайнци
1
@Heinzi: «легко выполнимо» - преуменьшение. Если я правильно помню, вторая или третья программа, которую я когда-либо писал, сделала именно это! ;-)
Иоахим Зауэр
1
Если Вселенная холост нити редактор, то , что струна теория? Вы не можете спорить с наукой, как это.
CorsiKa
22

Теоретически, все, что делает многопоточная программа, может быть выполнено и с помощью однопоточной программы, только медленнее.

На практике разница в скорости может быть такой большой, что невозможно использовать однопотоковую программу для этой задачи. Например, если у вас есть задание пакетной обработки данных, выполняемое каждую ночь, и для его завершения в одном потоке требуется более 24 часов, у вас нет другого выбора, кроме как сделать его многопоточным. (На практике пороговое значение, вероятно, еще меньше: часто такие задачи обновления должны завершаться к раннему утру, прежде чем пользователи снова начнут использовать систему. Кроме того, от них могут зависеть другие задачи, которые также должны завершиться в ту же ночь. доступное время выполнения может составлять всего несколько часов / минут.)

Выполнение вычислительной работы над несколькими потоками является формой распределенной обработки; Вы распределяете работу по нескольким потокам. Другим примером распределенной обработки (с использованием нескольких компьютеров вместо нескольких потоков) является заставка SETI: обработка большого количества данных измерений на одном процессоре займет очень много времени, и исследователи предпочли бы увидеть результаты до выхода на пенсию ;-) Однако они у нас нет бюджета, чтобы арендовать суперкомпьютер так долго, поэтому они распределяют работу по миллионам домашних ПК, чтобы сделать его дешевым.

Петер Тёрёк
источник
Заставка SETI является примером многопоточности в том смысле, что она запускается в фоновом потоке на вашем компьютере; вы все еще можете выполнять другие действия на своем компьютере, пока он обрабатывает данные в фоновом режиме. Без потока будет пауза, пока заставка SETI выполняет свои вычисления; вам придется подождать, пока он не закончится, прежде чем вы сможете продолжить свою собственную работу.
Роберт Харви
3
@ Роберт: Я думаю, что Петер использует SETI @ Home, чтобы объяснить концепцию разделения работы на несколько процессоров. Распределенные вычисления, конечно, отличаются от многопоточности, но концепция похожа.
Стивен
5
Я думаю, что пример SETI - это распределенные вычисления, а не многопоточные. Схожие понятия, но не одно и то же.
11

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

- Проблема с потоками (www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.pdf).

Несмотря на то, что при использовании потоков можно добиться некоторых преимуществ в плане производительности, которые позволяют распределять работу между несколькими ядрами, они часто имеют высокую цену.

Одним из недостатков использования потоков, которые еще не упомянуты здесь, является потеря разделения ресурсов, которые вы получаете с однопоточными пространствами процессов. Например, допустим, вы столкнулись с проблемой сегфоута. В некоторых случаях это можно исправить в многопроцессорном приложении, в котором вы просто позволяете погибающему ребенку умереть и возродите новое. Так обстоит дело в бэкэнде prefork в Apache. Когда один экземпляр httpd выходит из строя, в худшем случае конкретный HTTP-запрос может быть отброшен для этого процесса, но Apache порождает нового потомка и часто этот запрос, если его просто повторно отправить и обслужить. Конечным результатом является то, что Apache в целом не снесен с неисправным потоком.

Другое соображение в этом сценарии - утечки памяти. В некоторых случаях вы можете изящно обработать сбой потока (в UNIX возможно восстановление по некоторым специфическим сигналам - даже segfault / fpviolation -), но даже в этом случае вы могли вытечь всю память, выделенную этому потоку (malloc, new и т. д.). Таким образом, несмотря на то, что процесс может работать, он с течением времени теряет все больше и больше памяти при каждом сбое / восстановлении. Опять же, есть до некоторой степени способы минимизировать это, например использование Apache пулов памяти. Но это по-прежнему не защищает от памяти, которая могла быть выделена сторонними библиотеками, которые, возможно, использовал поток.

И, как отмечают некоторые люди, понимание примитивов синхронизации, пожалуй, самая сложная вещь, чтобы по-настоящему понять все правильно. Эта проблема сама по себе - просто правильная логика для всего вашего кода - может быть огромной головной болью. Таинственные тупики могут возникать в самые странные времена, а иногда даже до тех пор, пока ваша программа не будет запущена в производство, что делает отладку еще более сложной. Добавьте к этому тот факт, что примитивы синхронизации часто сильно различаются в зависимости от платформы (Windows и POSIX), и отладка часто может быть более сложной, а также возможность возникновения условий гонки в любое время (запуск / инициализация, время выполнения и завершение работы), программирование с потоками действительно мало для начинающих. И даже для экспертов, по-прежнему мало пощады только потому, что знание потоков само по себе не уменьшает сложность в целом. Кажется, что каждая строка многопоточного кода экспоненциально усугубляет общую сложность программы, а также увеличивает вероятность появления скрытого тупика или странного состояния гонки в любое время. Также может быть очень сложно написать контрольные примеры, чтобы найти эти вещи.

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

Несколько процессов, каждый из которых выполняет один поток выполнения, могут быть намного лучше, чем несколько потоков, запущенных в одном процессе. А с появлением большей части нового однорангового кода, такого как AMQP (RabbitMQ, Qpid и т. Д.) И ZeroMQ, стало намного проще разделять потоки по разным пространствам процессов и даже машинам и сетям, что значительно упрощает работу. Но все же, это не серебряная пуля. Есть еще сложность для решения. Вы просто перемещаете некоторые свои переменные из пространства процесса в сеть.

Суть в том, что решение войти в область потоков не является легким. Как только вы вступаете на эту территорию, почти мгновенно все становится более сложным, и в вашу жизнь входят новые виды проблем. Это может быть весело и круто, но это похоже на ядерную энергетику - когда дела идут плохо, они могут идти плохо и быстро. Я помню, как много лет назад посещал занятия по критике, и они показали фотографии некоторых ученых в Лос-Аламосе, которые играли с плутонием в лабораториях еще во Второй мировой войне. Многие предпринимали мало или вообще никаких мер предосторожности в случае воздействия, и в мгновение ока - одной яркой, безболезненной вспышкой, все это было бы для них закончено. Дни спустя они были мертвы. Ричард Фейнман позже назвал это « щекоткой хвоста дракона».Это похоже на игру с потоками (по крайней мере, для меня, во всяком случае). Сначала это кажется довольно безобидным, и к тому времени, как ты укусишься, почесал голову, как быстро все пошло плохо. Но, по крайней мере, темы победили. не убью тебя.

Майк Оуэнс
источник
Мой ответ TL; DR бледнеет по сравнению с этим прекрасным фрагментом о том, что отдельные темы не будут делать для вас.
bmike
1
перерыв на кофе во второй половине дня
Майк Оуэнс
10

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

Обдумайте альтернативу и сделайте ли это вас счастливым. Предположим, у вас есть несколько задач, которые должны выполняться одновременно. Например, вы должны поддерживать связь с двумя разными системами. Как вы делаете это без многопоточности? Вы, вероятно, создадите свой собственный планировщик и позволите ему вызывать различные задачи, которые необходимо выполнить. Это означает, что вам нужно разделить ваши задачи на части. Возможно, вам необходимо выполнить некоторые ограничения в реальном времени, вы должны убедиться, что ваши детали не занимают слишком много времени. В противном случае таймер истечет в других задачах. Это усложняет задачу разделения задачи. Чем больше задач вам нужно решить, тем больше вам нужно разделиться и тем сложнее станет ваш планировщик, чтобы удовлетворить все ограничения.

Когда у вас есть несколько потоков, жизнь может стать проще. Упреждающий планировщик может остановить поток в любое время, сохранить его состояние и перезапустить другой. Он перезапустится, когда ваша нить получит свою очередь. Преимущества: сложность написания планировщика уже сделана для вас, и вам не нужно разделять свои задачи. Кроме того, планировщик способен управлять процессами / потоками, о которых вы сами даже не подозреваете. А также, когда потоку ничего не нужно делать (он ожидает какого-то события), он не займет циклов ЦП. Это не так легко сделать, когда вы создаете свой однопоточный планировщик. (уложить что-то в сон не так сложно, но как оно просыпается?)

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

отметка
источник
9

Есть ли что-то, что может быть достигнуто только с помощью нескольких потоков?

Да. Вы не можете запускать код на нескольких процессорах или ядрах процессора в одном потоке.

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

грязевой
источник
6

Темы не только о скорости, но и о параллелизме.

Если у вас нет пакетного приложения, как предлагал @Peter, а вместо этого инструментарий с графическим интерфейсом, например, WPF, как вы можете взаимодействовать с пользователями и бизнес-логикой всего одним потоком?

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

Есть много сценариев, когда одного простого потока недостаточно. Вот почему последние достижения, такие как процессор Intel MIC с более чем 50 ядрами и сотнями потоков, имеют место.

Да, параллельное и параллельное программирование сложно. Но необходимо.

Рандольф Ринкон Фадул
источник
3
«Только один поток» может означать несколько вещей - например, вы можете использовать продолжения с разделителями для имитации совместной многозадачности внутри одного (ОС или зеленого) потока.
Фрэнк Шиарар
Конечно, но я даю немного контекста к вопросу @Frank +1 за совет.
Рандольф Ринкон Фадул
3
Потоки могут сделать это проще, но все задачи, которые вы упомянули, могут быть выполнены без потоков, и действительно были. Например, канонический цикл GUI имел обыкновение while (true) {обрабатывать события GUI; немного вычислить} Нет темы нужны.
KeithB
Существуют однопоточные однопоточные веб-серверы. Например, lighttpd, или thttpd, или nginx (хотя последний может запускать более одного процесса, но по умолчанию - один. Он также всегда однопоточный). У них абсолютно нет проблем с обслуживанием более одного пользователя.
StasM
6

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

LarsTech
источник
Это не совсем правильно. Теоретически, вы можете разделить вашу длинную операцию на множество более мелких и обновить обработку событий между ними.
Себастьян Неграсус
@Sebastion N. Но если длительный процесс не может быть преобразован в меньшие? Возможность запуска процесса в другом потоке может освободить поток GUI (основной поток), чтобы он по-прежнему реагировал.
LarsTech
5

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

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

bmike
источник
4

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

В этом может помочь добавление методов проверки в библиотеку ввода-вывода, чтобы увидеть, сколько можно прочитать без блокировки, но не все библиотеки дают полную гарантию на этот счет.

чокнутый урод
источник
Они могут быть однопоточными (и часто бывают). Код говорит ядру запустить IO и получает сигнал после его завершения. В ожидании сигнала он может выполнить другую обработку.
KeithB
@keith это не -blocking IO Я специально сказал , блокирование
трещотки урод
Но зачем вам блокировать IO, если вы хотите оставаться отзывчивым? Есть ли блокирующий ввод-вывод, который обычно не имеет неблокирующей альтернативы? Я не могу думать ни о чем.
KeithB
RMI @keith java блокирует, и в то время как вы можете реализовать обратный вызов (но это создает другой поток) с ним, но это может быть заблокировано брандмауэрами
ratchet freak
Это звучит как ограничение Java RMI, а не внутреннее ограничение однопоточного кода. Кроме того, если вы выполняете RMI, у вас есть отдельный «поток» выполнения, просто на удаленной машине.
KeithB
4

Множество хороших ответов, но я не уверен, что какая-то фраза будет такой же, как я бы - Возможно, это предлагает другой взгляд на это:

Потоки - это просто упрощение программирования, такое как Objects или Actors, или для циклов (Да, все, что вы реализуете с помощью циклов, вы можете реализовать с помощью if / goto).

Без потоков вы просто реализуете движок состояния. Мне приходилось делать это много раз (когда я впервые это делал, я никогда об этом не слышал - просто сделал большой оператор switch, управляемый переменной State). Конечные автоматы все еще довольно распространены, но могут раздражать. С нитями огромный кусок шаблона исчезает.

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

Java предоставляет «зеленые» потоки в системах, где ОС не предоставляет НИКАКОЙ поддержки потоков. В этом случае легче понять, что они явно не более чем абстракция программирования.

Билл К
источник
+1 - Потоки предоставляют просто абстракцию для параллелизма на в основном последовательных машинах, точно так же как языки программирования высокого уровня обеспечивают абстракцию машинного кода.
Mouviciel
0

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

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

кодировщик
источник
0

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

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

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

Хорошим примером является нечасто выполняемый код обработки ошибок. Скажем, задача сталкивается с очень редкой ошибкой, и код для обработки этой ошибки должен быть помещен в память. Если диск занят, и процесс имеет только один поток, продвижение вперед невозможно, пока код для обработки этой ошибки не будет загружен в память. Это может вызвать бурный ответ.

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

Дэвид Шварц
источник