Разница между "сопрограммой" и "потоком"? - PullRequest
122 голосов
/ 20 декабря 2009

В чем разница между "сопрограммой" и "нитью"?

Ответы [ 5 ]

134 голосов
/ 03 мая 2014

Первое чтение: Параллелизм и параллелизм - в чем разница?

Параллелизм - это разделение задач для обеспечения чередования выполнение. Параллелизм - это одновременное выполнение нескольких кусочки работы с целью увеличения скорости. - https://github.com/servo/servo/wiki/Design

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

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

В отличие от нитей, которые являются преимущественными, сопрограммные переключатели кооператив (программист контролирует, когда произойдет переключение). Ядро не участвует в сопрограммных переключателях. - http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

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

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

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

Генераторы сопрограмм и / или могут использоваться для реализации кооперативных функций. Вместо того, чтобы запускаться в потоках ядра и планироваться операционной системой, они работают в одном потоке до тех пор, пока не завершат работу или не завершат работу, уступая другим функциям, определенным программистом. Языки с генераторами , такие как Python и ECMAScript 6, могут использоваться для создания сопрограмм. Async / await (замечено в C #, Python, ECMAscript 7, Rust) - это абстракция, построенная поверх функций генератора, которые дают фьючерсы / обещания.

В некоторых контекстах сопрограммы могут ссылаться на стековые функции, в то время как генераторы могут ссылаться на стековые функции.

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

Например, у Java было " зеленых потоков "; это были потоки, которые были запланированы виртуальной машиной Java (JVM), а не изначально в потоках ядра базовой операционной системы. Они не работают параллельно и не используют преимущества нескольких процессоров / ядер - поскольку для этого потребуется собственный поток! Поскольку они не были запланированы ОС, они были больше похожи на сопрограммы, чем на потоки ядра. Зеленые потоки - это то, что использовала Java, пока в Java 1.2 не были введены собственные потоки.

Потоки потребляют ресурсы. В JVM каждый поток имеет свой собственный стек, обычно размером 1 МБ. 64 КБ - это наименьшее количество стекового пространства, разрешенное для каждого потока в JVM. Размер стека потока может быть настроен в командной строке для JVM. Несмотря на название, потоки не являются свободными, поскольку их ресурсам использования, таким как каждому потоку, необходим собственный стек, локальное хранилище потоков (если оно есть) и стоимость планирования потоков / переключения контекста / аннулирования кэша ЦП. Это одна из причин того, почему сопрограммы стали популярными для приложений, критичных к производительности, с высокой степенью одновременности.

Mac OS позволяет процессу выделять только около 2000 потоков, а Linux выделяет 8 МБ стека на поток и разрешает только столько потоков, сколько умещается в физической ОЗУ.

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

91 голосов
/ 20 декабря 2009

Сопрограммы - это форма последовательной обработки: только одна выполняется в любой момент времени (точно так же, как подпрограммы AKA-процедуры AKA-функции - они просто передают эстафету друг другу более плавно).

Потоки - это (по крайней мере, концептуально) форма параллельной обработки: несколько потоков могут выполняться в любой момент времени. (Традиционно на одноядерных, одноядерных машинах этот параллелизм моделировался с некоторой помощью ОС - в настоящее время, так как многие машины являются многопроцессорными и / или многоядерными, потоки будут де-факто выполнять одновременно, а не просто «концептуально»).

83 голосов
/ 16 января 2016

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

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

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

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

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

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

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

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

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

16 голосов
/ 20 декабря 2009

Одним словом: упреждение. Сопрограммы действуют как жонглеры, которые продолжают передавать друг другу хорошо отрепетированные очки. Потоки (истинные потоки) могут быть прерваны практически в любой точке, а затем возобновлены позже. Конечно, это приводит к возникновению всевозможных проблем с конфликтом ресурсов, отсюда и печально известный GIL от Python - Global Interpreter Lock.

Многие реализации потоков на самом деле больше похожи на сопрограммы.

8 голосов
/ 20 декабря 2009

Это зависит от языка, который вы используете. Например, в Lua это одно и то же (тип переменной сопрограммы называется thread).

Обычно, хотя сопрограммы осуществляют добровольную уступку, когда (вы) программист решает, где yield, т. Е. Передает контроль другой подпрограмме.

Вместо этого потоки автоматически управляются (останавливаются и запускаются) ОС, и они могут одновременно выполняться на многоядерных процессорах.

...