Что такое сопрограмма?


204

Что такое сопрограмма? Как они связаны с параллелизмом?


2
Параллельный код не обязательно должен выполняться в «параллельном» режиме (давайте не будем вводить новые термины).
lucid_dreamer

2
Я написал одну сопрограммную библиотеку со стандартным C, поддерживающую сообщения select / poll / eplll / kqueue / iocp / Win GUI для Linux, BSD и Windows. Это проект с открытым исходным кодом в github.com/acl-dev/libfiber . Совет будет добро пожаловать.
ShuXin Zheng

Более интересная информация здесь: stackoverflow.com/q/16951904/14357
spender

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

сопрограммное это функция , которая может приостановить исполнение до достижения возвращения, и это косвенно может передать управление другой сопрограмме в течение некоторого времени.
hassanzadeh.sd

Ответы:


138

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

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


19
В чем разница между вызовом функции напрямую и выходом из сопрограммы с переносом этой функции в эту сопрограмму?
Мин Ли

3
Может быть, лучше объяснить, что эти два понятия в этом контексте не являются действительно «ортогональными». Вы можете определенно нарисовать, как эти два понятия похожи друг на друга. Идея передачи контроля между двумя или более вещами очень похожа.
steviejay

8
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning.<- Это является параллелизм. Слово, которое вы ищете, это параллелизм.
Адам Арольд

@steviejay orthogonal = Not similar to each other?
tonix

1
@tonix Мне сказали, что это orthogonalозначает "независимые друг от друга".
Рик

77

Из раздела Программирование на Lua , Coroutinesраздел " ":

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

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

Для " concurrency" вы можете сослаться на слайд Роба Пайка :

Параллелизм - это состав самостоятельно выполняемых вычислений.

Таким образом, во время выполнения сопрограммы A она передает управление сопрограмме B. Затем через некоторое время сопрограмма B передает управление обратно сопрограмме A. Поскольку существует зависимость между сопрограммами, и они должны работать в тандеме, поэтому две сопрограммы не являются параллельными .


6
Сопрограммы не выполняются самостоятельно. Они сменяются, каждый ждет, пока другой выполнит какую-то часть работы. Они активно координируют друг с другом. Это противоположность определения параллелизма Роба Пайкса.
Эрик Дж. Хагстрем

2
@ ErickG.Hagstrom: Хотя они не выполняются независимо, логика каждой сопрограммы может быть независимой, верно? Если это правильно, то это как неперегрузочная ОС, работающая на одноядерном процессоре: один процесс должен отказаться от процессора, чтобы запустить другие задачи.
Нань Сяо

6
Существует разница между отказом ЦП для запуска какой-то другой задачи и сообщением некоторому другому конкретному процессу о том, что пора выполнять. Сопрограммы делают последнее. Это не зависит ни в каком смысле.
Эрик Дж. Хагстрем

7
@ChrisClark Я согласен с тобой. Сопрограммы параллельны. Вот некоторая цитата из Википедии: сопрограммы очень похожи на темы. Однако сопрограммы являются многозадачными, в то время как потоки обычно многозадачными. Это означает, что они обеспечивают параллелизм, но не параллелизм .
smwikipedia

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

47

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

Я нашел этот ответ очень полезным:

https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9

Цитировать от Идана Арье:

Чтобы развить вашу историю, я бы сказал так:

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

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

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


6
Очень простая и понятная иллюстрация. +1 за это.
Таслит Осень

отличная иллюстрация. Я построил похожую историю - стоя в очереди, ожидая, чтобы собрать посылку. но на сегодняшний день ваш намного реалистичнее, кто стоит в очереди, когда идут поставки door2door? Lol
Аполак

1
Это потрясающее объяснение. Из самой цитаты это супер понятно.
Фаррух Хабибуллаев

15

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


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

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

В основном, есть два типа сопрограмм:

  1. Stackless
  2. Stackful

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

Это функции для запуска сопрограммы:

launch{}

async{}

Вы можете узнать больше здесь:

https://www.kotlindevelopment.com/deep-dive-coroutines/

https://blog.mindorks.com/what-are-coroutines-in-kotlin-bf4fecd476e9


1
Хороший ответ! Полезно для разработчиков Kotlin и Android.
Малвиндер Сингх

5

С другой стороны, в geventбиблиотеке Python есть coroutineсетевая библиотека, которая предоставляет вам нитевидные функции, такие как асинхронные сетевые запросы, без дополнительных затрат на создание и уничтожение потоков. coroutineБиблиотека используется greenlet.


2

Из Python Coroutine :

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

Из сопрограмм (C ++ 20)

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

Сравните с ответом другого:

На мой взгляд, возобновленная более поздняя часть - это принципиальное отличие, как у @ Twinkle's.
Хотя многие поля документа все еще находятся в стадии разработки, тем не менее, эта часть похожа на большинство ответов, за исключением @Nan Xiao's

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

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

Отношение с одновременным:
есть часть «Выполнение» сопрограмм (C ++ 20). Слишком долго цитировать здесь.
Помимо деталей, есть несколько состояний.

When a coroutine begins execution  
When a coroutine reaches a suspension point  
When a coroutine reaches the co_return statement  
If the coroutine ends with an uncaught exception  
When the coroutine state is destroyed either because it terminated via co_return or uncaught exception, or because it was destroyed via its handle 

как комментарий @Adam Arold под ответом @ user217714. Это параллелизм.
Но это отличается от многопоточности. из std :: thread

Потоки позволяют выполнять несколько функций одновременно. Потоки начинают выполнение сразу после создания соответствующего объекта потока (в ожидании любых задержек планирования ОС), начиная с функции верхнего уровня, предоставленной в качестве аргумента конструктора. Возвращаемое значение функции верхнего уровня игнорируется, и, если оно завершается выдачей исключения, вызывается std :: terminate. Функция верхнего уровня может передавать свое возвращаемое значение или исключение вызывающей стороне через std :: обещание или путем изменения общих переменных (для этого может потребоваться синхронизация, см. Std :: mutex и std :: atomic)

Так как это параллелизм, он работает как многопоточность, особенно когда ожидание неизбежно (с точки зрения ОС), поэтому также сбивает с толку.


1

Сопрограмма - это особый вид подпрограммы. Вместо того, чтобы отношения «ведущий-ведомый» между вызывающим и вызываемой подпрограммой, существующие с обычными подпрограммами, вызывающий и вызываемые сопрограммы более справедливы.

  • Сопрограмма - это подпрограмма, которая имеет несколько записей и сама управляет ими - поддерживается непосредственно в Lua

  • Также называется симметричным управлением: вызывающий и вызываемые сопрограммы находятся на более равной основе.

  • Вызов сопрограммы называется резюме

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

  • Сопрограммы неоднократно возобновляют друг друга, возможно, навсегда

  • Сопрограммы обеспечивают квази-параллельное выполнение программных блоков (сопрограммы); их исполнение чередуется, но не перекрывается

Example1 Example2


1

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

  1. что является параллельным (программным)?

цитируется из "программирования Erlang" Джо Армстронга, легендарного:

Параллельная программа может работать потенциально быстрее на параллельном компьютере.

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

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

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

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

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

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

  1. сопрограмма и параллелизм

Слово «сопрограмма» состоит из двух слов: «со» (кооператив) и «рутина» (функции).

а. это достигает параллелизма или параллелизма?

Проще говоря, давайте обсудим это на одноядерном компьютере.

Параллельность достигается за счет доли времени от ОС. Поток выполняет свой код в назначенные ему временные рамки на ядре ЦП. Это может быть прервано ОС. Это также может дать контроль над ОС.

Сопрограмма, с другой стороны, передает управление другой сопрограмме в потоке, а не ОС. Таким образом, все сопрограммы в потоке все еще используют временные рамки для этого потока, не уступая ядру ЦП другим потокам, управляемым ОС.

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

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

б. разница с вызовом функции?

введите описание изображения здесь

Как показано на рисунке, returnдля переключения управления не нужно звонить . Это может дать без return. Сопрограмма сохраняет и разделяет состояние в текущем фрейме функции (стеке). Так что это намного легче, чем функция, так как вам не нужно сохранять регистры и локальные переменные в стеке и перематывать стек вызовов, когда call ret.


0

Я буду расширять ответ @ user21714. Сопрограммы - это независимые пути выполнения, которые не могут выполняться одновременно. Они зависят от контроллера - например, pythonбиблиотеки контроллера - для обработки переключения между этими путями. Но для этого для работы самих сопрограмм нужно вызватьyield или подобные структуры, которые позволяют приостановить их выполнение.

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

Вы можете увидеть этот эффект, запустив многопоточную программу - например, jvmприложение - в котором используются все восемь ваших core i7ядер с гиперпоточностью: вы можете увидеть 797% использования в Activity Monitorили Top. Вместо этого при запуске типичной pythonпрограммы, даже с coroutinesили, python threadingиспользование будет максимально на 100%. Т.е. одна машина с гиперпоточностью.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.