В чем разница между "сопрограммой" и "нитью"?
Разница между "сопрограммой" и "нитью"?
Ответ 1
Coroutines - это форма последовательной обработки: только один выполняется в любой момент времени (так же, как подпрограммы AKA-процедур AKA-функции - они просто передают эстафету между собой более плавно).
Темы (по крайней мере концептуально) представляют собой одну из форм параллельной обработки: несколько потоков могут выполняться в любой момент времени. (Традиционно, на однопроцессорных одноядерных машинах, которые concurrency моделировались с некоторой помощью от ОС - в наши дни, так как многие машины являются многопроцессорными и/или многоядерными, потоки де-факто будут выполняться одновременно, не только "концептуально" ).
Ответ 2
Сначала прочитайте: Concurrency vs Parallelism - В чем разница?
Concurrency - это разделение задач для обеспечения чередования выполнение. Parallelism - это одновременное выполнение нескольких куски работы, чтобы увеличить скорость. - https://github.com/servo/servo/wiki/Design
Краткий ответ: В потоках операционная система переключает потоки в соответствии с планировщиком, что является алгоритмом в ядре операционной системы. С сопрограммами программист и язык программирования определяют, когда нужно переключать сопрограммы; другими словами, задачи совместно многозадачны путем приостановки и возобновления функций в заданных точках, как правило (но не обязательно) в пределах одного потока.
Длинный ответ: В отличие от потоков, которые предварительно запланированы операционной системой, коммутаторы coroutine являются совместными, что означает, что программист (и, возможно, язык программирования и его время выполнения) контролирует, когда переключатель произойдет.
В отличие от потоков, которые являются преимущественными, коммутаторы coroutine кооператив (программист контролирует, когда произойдет переход). Ядро не участвует в коммутаторах coroutine. - http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html
Язык, который поддерживает собственные потоки, может выполнять свои потоки (потоки пользователей) в потоках операционной системы (потоки ядра). Каждый процесс имеет хотя бы один поток ядра. Потоки ячеек подобны процессам, за исключением того, что они совместно используют пространство памяти в процессе их владения со всеми другими потоками в этом процессе. Процесс "владеет" всеми его назначенными ресурсами, такими как память, файловые дескрипторы, сокеты, дескрипторы устройств и т.д., И эти ресурсы распределены между его потоками ядра.
Планировщик операционной системы является частью ядра, которое запускает каждый поток в течение определенного времени (на однопроцессорной машине). Планировщик выделяет время (временное выделение) для каждого потока, и если поток не завершен в течение этого времени, планировщик предварительно освобождает его (прерывает его и переключается на другой поток). Несколько потоков могут выполняться параллельно на многопроцессорной машине, так как каждый поток может (но необязательно должен быть) запланирован на отдельный процессор.
На однопроцессорной машине потоки быстро и быстро выгружаются (переключаются между ними) (в Linux по умолчанию используется временной интервал 100 мс), что делает их параллельными. Тем не менее, они не могут запускаться параллельно (одновременно), поскольку одноядерный процессор может запускать только одну вещь за раз.
Coroutines и/или генераторы могут использоваться для реализации совлокальных функций. Вместо того, чтобы запускаться на потоках ядра и планироваться операционной системой, они запускаются в одном потоке до тех пор, пока они не уступят или не закончатся, что приведет к другим функциям, определенным программистом. Языки с генераторами, такими как Python и ECMAScript 6, могут использоваться для создания сопрограмм. Async/await (см. С#, Python, ECMAscript 7, Rust) - абстракция, построенная поверх функций генератора, которые дают фьючерсы / promises.
В некоторых контекстах сопрограммы могут ссылаться на стековые функции, а генераторы могут ссылаться на функции без стека.
Волосы, легкие потоки и зеленые темы - это другие имена для сопроводительных и сопрограммных вещей. Иногда они могут выглядеть (как правило, по назначению) более похожими на потоки операционной системы на языке программирования, но они не работают параллельно, как настоящие потоки, а вместо этого работают как сопрограммы. (В зависимости от языка или реализации могут быть более конкретные технические особенности или различия между этими понятиями.)
Например, Java имеет " зеленые потоки"; это потоки, которые были запланированы виртуальной машиной Java (JVM), а не изначально на потоки ядра операционной системы. Они не запускались параллельно или не использовали несколько процессоров/ядер - поскольку для этого потребуется собственный поток! Поскольку они не были запланированы ОС, они были скорее похожими на сопрограммы, чем потоки ядра. Зеленые потоки - это то, что использовала Java, до тех пор, пока в Java 1.2 не появились собственные потоки.
Потоки потребляют ресурсы. В JVM каждый поток имеет свой собственный стек, обычно размером 1 МБ. 64k - это наименьшее количество пространства стека, разрешенного для потока в JVM. Размер стека потоков можно настроить в командной строке для JVM. Несмотря на название, потоки не являются бесплатными из-за их ресурсов использования, таких как каждый поток, требующий собственного стека, локальное хранилище потоков (если оно есть) и стоимость переноса нестационарного потока/контекстного переключения/отказа кэша ЦП. Это связано с тем, что сопрограммы стали популярными для высокопроизводительных критически важных приложений.
Mac OS разрешит процессу выделять около 2000 потоков, а Linux выделяет 8 МБ стека на поток и будет разрешать столько потоков, которые будут вписываться в физическую память.
Следовательно, потоки - это самый тяжелый вес (с точки зрения использования памяти и времени переключения контекста), затем сопрограммы и, наконец, генераторы - самый легкий вес.
Ответ 3
Примерно через 7 лет, но в ответах здесь отсутствует некоторый контекст для совлокальных процедур и потоков. Почему сопрограммы получают так много внимания в последнее время, и когда я буду использовать их по сравнению с потоками?
Прежде всего, если сопрограммы выполняются одновременно (никогда не в параллельно), почему кто-то предпочитает их по потокам?
Ответ заключается в том, что сопрограммы могут обеспечить очень высокий уровень concurrency с очень небольшими накладными расходами. Как правило, в потоковой среде у вас есть не более 30-50 потоков, прежде чем количество накладных расходов, фактически планирующих эти потоки (системным планировщиком), значительно сокращает время, в течение которого потоки действительно полезны.
Хорошо, так что с потоками вы можете иметь parallelism, но не слишком много parallelism, разве это не лучше, чем совместная процедура, запущенная в одном потоке? Ну не обязательно. Помните, что совместная процедура все еще может выполнять concurrency без накладных расходов планировщика - она просто управляет самой коммутацией контекста.
Например, если у вас есть подпрограмма, выполняющая некоторую работу, и она выполняет операцию, которую вы знаете, будет блокироваться в течение некоторого времени (т.е. сетевой запрос), с помощью совместной процедуры вы можете немедленно переключиться на другую процедуру без накладных расходов, включая системный планировщик в этом решении - да, вы, программист должны указывать, когда могут переключаться совлокальные подпрограммы.
С большим количеством подпрограмм, выполняющих очень маленькие кусочки работы и добровольно переключающимися между собой, вы достигли такого уровня эффективности, которого планировщик никогда не смог бы достичь. Теперь вы можете иметь тысячи сопрограмм, работающих вместе, в отличие от десятков потоков.
Поскольку ваши подпрограммы теперь переключаются между собой заранее определенными точками, теперь вы также можете избегать блокировки в общих структурах данных (потому что вы никогда не скажете, что ваш код переключится на другую сопрограмму в середине критический раздел)
Другим преимуществом является гораздо более низкое использование памяти. В поточной модели каждый поток должен выделять свой собственный стек, и поэтому использование вашей памяти линейно растет с количеством потоков, которые у вас есть. С совместными подпрограммами количество подпрограмм, которые у вас есть, не имеет прямой зависимости от использования вашей памяти.
И, наконец, совлокальные подпрограммы получают много внимания, потому что на некоторых языках программирования (таких как Python) ваши потоки не могут работать параллельно в любом случае - они запускаются одновременно точно так же, как сопрограммы, но без низкой памяти и свободных накладных расходов.
Ответ 4
Одним словом: preemption. Короуты действуют как жонглеры, которые продолжают передавать друг другу хорошо отрепетированные очки. Темы (истинные потоки) могут быть прерваны практически в любой точке, а затем возобновлены позже. Конечно, это приносит с собой всевозможные проблемы с конфликтами ресурсов, поэтому Python печально известен GIL - Global Interpreter Lock.
Многие реализации потоков на самом деле больше похожи на сопрограммы.
Ответ 5
Это зависит от языка, который вы используете. Например, в Lua они - одно и то же (тип переменной coroutine называется thread
).
Обычно cooutines реализует добровольный доход, где (вы) программист решает, где yield
, т.е. дать управление другой процедуре.
Вместо этого потоки автоматически управляются (останавливаются и запускаются) операционной системой, и они могут даже запускаться одновременно на многоядерных процессорах.