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

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


person yesraaj    schedule 16.02.2009    source источник
comment
Параллельный код не обязательно должен выполняться параллельно (давайте не будем вводить новые термины).   -  person lucid_dreamer    schedule 30.01.2018
comment
Я написал одну библиотеку сопрограмм на стандартном C, поддерживающую сообщения графического интерфейса select / poll / eplll / kqueue / iocp / Win для Linux, BSD и Windows. Это проект с открытым исходным кодом в github.com/acl-dev/libfiber. Совет будет добро пожаловать.   -  person ShuXin Zheng    schedule 24.02.2018
comment
Более интересная информация здесь: stackoverflow.com/q/16951904/14357   -  person spender    schedule 07.12.2018
comment
Я могу представить, что этот вопрос будет отвергнут, если его зададут в нынешнюю эпоху. Не уверен, почему существует такая огромная разница в восприятии сообщества по сравнению с тем, что было раньше?   -  person tnkh    schedule 23.05.2019
comment
сопрограмма - это функция, которая может приостанавливать свое выполнение до достижения возврата, и она может косвенно передавать управление другой сопрограмме на некоторое время.   -  person hassanzadeh.sd    schedule 07.10.2019
comment
Иисус. Все ответы здесь заведомо неверны.   -  person Konrad Rudolph    schedule 03.06.2020
comment
@KonradRudolph, не могли бы вы объяснить, что такое сопрограмма? Самый популярный ответ не сопровождается объяснением в Википедии.   -  person reyad    schedule 12.10.2020
comment
@reyad Вкратце, Википедия права, ответы неверны (в частности, сопрограммы реализуют параллелизм, что прямо противоречит тому, что ложно утверждают множественные ответы). Ответ «Изаны», который был написан после моего комментария, правильный. yield генераторы в Python являются примером сопрограмм. async объявляет, что это полноценная сопрограмма.   -  person Konrad Rudolph    schedule 13.10.2020
comment
Я только что завершил всю статью в Википедии о сопрограммах и правильно ее понял. У меня все еще есть одна путаница, это на самом деле на уровне реализации. Может ли сопрограмма существовать в двух отдельных потоках и по-прежнему вызывать друг друга (т.е. переключаться между ними)? Согласно wikipedia switching between coroutines need not involve any system calls or any blocking calls whatsoever, сопрограмма должна быть легкой. Не могли бы вы прояснить это для меня? Потому что горутина создает потоки. То же самое и с lua?   -  person reyad    schedule 13.10.2020


Ответы (11)


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

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

person user21714    schedule 16.02.2009
comment
В чем разница между прямым вызовом функции и выходом из сопрограммы с переносом этой функции в эту сопрограмму? - person Ming Li; 04.08.2014
comment
Тогда было бы лучше объяснить, что эти два понятия не совсем «ортогональны» в этом контексте. Вы определенно можете нарисовать, как эти две концепции похожи друг на друга. Идея передачи управления между двумя или более объектами очень похожа. - person steviesh; 08.08.2017
comment
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning. ‹- Это параллелизм. Слово, которое вы ищете, - это параллелизм. - person Adam Arold; 10.12.2018
comment
@steviejay orthogonal = Not similar to each other? - person tonix; 15.10.2019
comment
@ user21714 Я думал, что yield Python - это языковая конструкция для реализации generators, которые по сути являются подмножеством coroutines. Если говорить о чистом coroutines, то управление возвращается не вызывающей функции, а другой сопрограмме. Что вы можете сказать по этому поводу? - person tonix; 15.10.2019
comment
@tonix Мне сказали, что orthogonal означает независимость друг от друга. - person Rick; 10.02.2020

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

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

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

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

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

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

person Nan Xiao    schedule 01.07.2015
comment
Я любил этот ответ, пока не добрался до последнего предложения. Что это значит? Вы неправильно написали параллелизм? Если да, то этот вывод, похоже, не соответствует приведенному определению. Или это должно быть новое слово «совпадение»? Что означает это слово? - person Erick G. Hagstrom; 21.06.2016
comment
@ ErickG.Hagstrom: Извините, я неправильно написал concurrency. Как вы думаете, почему заключение не соответствует приведенному определению? - person Nan Xiao; 22.06.2016
comment
Сопрограммы не выполняются независимо. Они по очереди ждут, пока другой выполнит какую-то часть работы. Они активно координируют друг друга. Это противоположно определению параллелизма Роба Пайкса. - person Erick G. Hagstrom; 22.06.2016
comment
@ ErickG.Hagstrom: Хотя они не выполняются независимо, логика каждой сопрограммы может быть независимой, верно? Если это верно, это похоже на невытесняющую ОС, работающую на одноядерном ЦП, один процесс должен отказаться от ЦП, чтобы позволить другим задачам работать. - person Nan Xiao; 22.06.2016
comment
Есть разница между отказом от ЦП, чтобы позволить другой задаче работать, и сообщением какому-то другому процессу, что пора выполнить. Второе делают сопрограммы. Это не является независимым ни в каком смысле. - person Erick G. Hagstrom; 22.06.2016
comment
Придется согласиться с тем, что последнее предложение просто не следует (фактически, противоречит) самому ответу. Полный ответ доказывает, что сопрограммы, по определению, НЕ параллельны - они, по сути, являются взаимоисключающими (никакие две из них не могут выполняться одновременно). - person Gerasimos R; 28.11.2016
comment
@ ErickG.Hagstrom: Да, ты прав. Я обновил ответ, спасибо! - person Nan Xiao; 29.11.2016
comment
@GerasimosR: Да, ты прав. Я обновил ответ, спасибо! - person Nan Xiao; 29.11.2016
comment
@NanXiao, раз уж вы на сайте Роба Пайка: Роб специально имел в виду эту цитату, чтобы обозначить, что сопрограммы являются параллельными, потому что сопрограммы позволяют обрабатывать несколько вещей одновременно. Сопрограммы допускают совместную многозадачность. На следующем слайде Пайк противопоставляет это параллелизму, который является еще одной формой параллелизма, но имеет другие последствия. - person Chris Clark; 15.02.2017
comment
@ChrisClark Я согласен с вами. Сопрограммы - это параллелизм. Вот цитата из Википедии: Сопрограммы очень похожи на потоки. Однако сопрограммы являются многозадачными совместно, тогда как потоки обычно выполняют многозадачность с вытеснением. Это означает, что они обеспечивают параллелизм, но не параллелизм. - person smwikipedia; 05.10.2018
comment
И: Кооперативная многозадачность, также известная как невытесняющая многозадачность, представляет собой стиль многозадачности компьютера, при котором операционная система никогда не инициирует переключение контекста с запущенного процесса на другой процесс. Вместо этого процессы добровольно передают управление периодически, когда они простаивают или логически заблокированы, чтобы позволить нескольким приложениям работать одновременно. - person smwikipedia; 05.10.2018
comment
Итак, правильно ли я понимаю, что сопрограммы не похожи на кооперативную многозадачность в том смысле, что сопрограмма сообщает о выполнении определенной другой задачи, а не просто позволяет следующей в очереди? - person Adrian; 04.05.2019

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

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

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

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

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

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

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

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

person mr1031011    schedule 07.12.2018
comment
Очень простая и понятная иллюстрация. +1 за это. - person Taslim Oseni; 02.01.2019
comment
отличная иллюстрация. Я построил похожую историю - стоя в очереди, чтобы забрать посылку. но на сегодня ваш гораздо более реалистичен, кто стоит в очереди, когда идут поставки door2door? Ржу не могу - person apolak; 18.04.2019
comment
Замечательное объяснение. Из самой цитаты это очень понятно. - person Farruh Habibullaev; 19.06.2019
comment
Это делает все остальные объяснения здесь более понятными. Код - это набор инструкций ЦП. Сопрограммы позволяют выполнять инструкции, ожидая завершения задач вне ЦП. - person wamster; 11.04.2021

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

person Twinkle    schedule 21.06.2016
comment
Это не так похоже на потоки, которые работают независимо и одновременно (отдельные ядра параллельно). Кроме того, сравнение подпрограмм не выполняется в том смысле, что существует несколько независимых путей выполнения, и они не возвращают друг другу результаты. - person WestCoastProjects; 24.03.2020

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

По сути, есть два типа сопрограмм:

  1. Без стека
  2. Много

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

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

launch{}

async{}

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

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

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

person Dhaval Jivani    schedule 07.10.2017
comment
Хороший ответ! Полезно для разработчиков на Kotlin и Android. - person Malwinder Singh; 06.04.2020

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

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

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

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

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

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

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

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

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

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

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

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

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

Для простоты давайте обсудим это на одноядерном компьютере.

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

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

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

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

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

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

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

person Izana    schedule 24.06.2020

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

person joseph    schedule 12.04.2017

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

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

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

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

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

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

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

Example1  Example2

person BoraKurucu    schedule 02.06.2020

Из Python Coroutine:

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

Из Coroutines (C ++ 20)

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

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

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

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

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

Связь с одновременным использованием:
В Coroutines (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 :: prom или путем изменения общих переменных (для чего может потребоваться синхронизация, см. Std :: mutex и std :: atomic)

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

person Shihe Zhang    schedule 31.05.2019

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

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

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

person WestCoastProjects    schedule 24.03.2020

[синхронный и асинхронный]

[Параллелизм против параллелизма]

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

Что касается Kotlin Coroutines:

Coroutine - это синтетический сахар / дополнительный слой, который позволяет выполнять большую задачу без блокировки и без обратных вызовов. Сопрограмма состоит из нескольких классов (Job, Dispatcher, Scope, Builder) и body

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

Давайте рассмотрим пример

suspend fun downloadFile(): File {
    //logic
}

suspend fun saveFile(file: File) {
    //logic
}

GlobalScope.launch {
    val downloadResult = downloadFile() //suspend function
    show(downloadResult) //UI 
    saveFile(downloadResult) //suspend function
}

Он создает Continuation класс, который state machine с функцией invokeSuspend()

class Continuation {
    File file;
 
    void invokeSuspend(Object result) {
        switch (label) {
            case 0: {
                label = 1;
                downloadFile(this); //suspend function
                return;
            }
            case 1: {
                file = (File) result;
                show(file); //UI
                saveFile(file, this); //suspend function
                return;
            }
        }
    }
}

приостановлено

  • просто маркер для работы с Continuation - передает продолжение в функцию
  • разделяет конечный автомат, что означает, что он может приостановить автомат
  • должен использовать обратный вызов, внутри которого вызывает Continuation.resume() -> Continuation.invokeSuspend()

Главное, что поведение coroutine полностью зависит от реализации библиотеки.

person yoAlex5    schedule 06.12.2020