Что такое сопрограмма? Как они связаны с параллелизмом?
Что такое сопрограмма?
Ответы (11)
Сопрограммы и параллелизм в значительной степени ортогональны. Сопрограммы - это общая структура управления, посредством которой управление потоком совместно передается между двумя разными подпрограммами без возврата.
Оператор yield в Python является хорошим примером. Создает сопрограмму. Когда встречается 'yield', текущее состояние функции сохраняется, и управление возвращается вызывающей функции. Затем вызывающая функция может передать выполнение обратно вызывающей функции, и ее состояние будет восстановлено до точки, в которой был обнаружен «yield», и выполнение будет продолжено.
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning. ‹- Это параллелизм. Слово, которое вы ищете, - это параллелизм.
- person Adam Arold; 10.12.2018
orthogonal = Not similar to each other?
- person tonix; 15.10.2019
yield Python - это языковая конструкция для реализации generators, которые по сути являются подмножеством coroutines. Если говорить о чистом coroutines, то управление возвращается не вызывающей функции, а другой сопрограмме. Что вы можете сказать по этому поводу?
- person tonix; 15.10.2019
orthogonal означает независимость друг от друга.
- person Rick; 10.02.2020
Из Программирование в Lua, раздел «Coroutines»:
Сопрограмма похожа на поток (в смысле многопоточности): это строка выполнения со своим собственным стеком, собственными локальными переменными и собственным указателем инструкции; но он разделяет глобальные переменные и в основном все остальное с другими сопрограммами. Основное различие между потоками и сопрограммами состоит в том, что концептуально (или буквально, в многопроцессорной машине) программа с потоками запускает несколько потоков параллельно. С другой стороны, сопрограммы являются совместными: в любой момент времени программа с сопрограммами запускает только одну из своих сопрограмм, и эта запущенная сопрограмма приостанавливает свое выполнение только тогда, когда она явно запрашивает приостановку.
Итак, суть в следующем: Сопрограммы являются «совместными». Даже в многоядерной системе в любой момент времени работает только одна сопрограмма (но несколько потоков могут выполняться параллельно). Между сопрограммами нет вытеснения, работающая сопрограмма должна явно отказаться от выполнения.
Для "concurrency" вы можете обратиться к слайду Роба Пайка:
Параллелизм - это композиция независимо выполняемых вычислений.
Таким образом, во время выполнения сопрограммы A она передает управление сопрограмме B. Затем через некоторое время сопрограмма B передает управление обратно сопрограмме A. Поскольку между сопрограммами существует зависимость, и они должны выполняться в тандеме, поэтому две сопрограммы не являются параллельными.
concurrency. Как вы думаете, почему заключение не соответствует приведенному определению?
- person Nan Xiao; 22.06.2016
Я считаю, что большинство ответов слишком технические, хотя это технический вопрос. Мне было трудно понять процесс сопрограммы. Я вроде как понимаю, но не понимаю одновременно.
Я нашел этот ответ здесь очень полезным:
https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9
Цитата из Идана Арье:
Чтобы развить вашу историю, я бы сказал примерно так:
Вы начинаете смотреть мультик, но это вступление. Вместо того, чтобы смотреть вступление, вы переключаетесь в игру и входите в онлайн-лобби, но для этого нужны 3 игрока, и в нем только вы и ваша сестра. Вместо того, чтобы ждать, пока к вам присоединится другой игрок, вы переключаетесь на домашнее задание и отвечаете на первый вопрос. Во втором вопросе есть ссылка на видео на YouTube, которое вам нужно посмотреть. Открываешь - и начинается загрузка. Вместо того, чтобы ждать, пока он загрузится, вы снова переключаетесь на мультфильм. Вступление окончено, можете смотреть. Сейчас есть реклама - а пока к игре присоединился третий игрок, и вы переключаетесь в игру И так далее ...
Идея в том, что вы не просто так быстро переключаете задачи, чтобы казалось, будто вы делаете все сразу. Вы используете время, которое вы ожидаете, чтобы что-то случилось (IO), для других дел, требующих вашего непосредственного внимания.
Обязательно проверьте ссылку, есть еще много чего, что я не могу все процитировать.
Сопрограмма похожа на подпрограмму / потоки. Разница в том, что после того, как вызывающий объект вызвал подпрограмму / потоки, он никогда не вернется к функции вызывающего. Но сопрограмма может вернуться обратно к вызывающей стороне после выполнения некоторого фрагмента кода, позволяя вызывающей стороне выполнить часть своего собственного кода и вернуться к точке сопрограммы, где она остановила выполнение, и продолжить оттуда. т.е. У сопрограммы более одной точки входа и выхода.
- Сопрограммы - отличные функции, доступные в языке Kotlin.
- Сопрограммы - это новый способ написания асинхронного, неблокирующего кода (и многого другого).
- Coroutine - это легкие потоки. Облегченный поток означает, что он не сопоставляется с собственным потоком, поэтому не требует переключения контекста на процессоре, поэтому они работают быстрее.
- он не отображается в собственном потоке
- И сопрограммы, и потоки многозадачны. Но разница в том, что потоки управляются ОС, а сопрограммы - пользователями.
По сути, есть два типа сопрограмм:
- Без стека
- Много
Kotlin реализует сопрограммы без стека - это означает, что сопрограммы не имеют собственного стека, поэтому они не отображаются в собственном потоке.
Это функции для запуска сопрограммы:
launch{}
async{}
Вы можете узнать больше здесь:
https://www.kotlindevelopment.com/deep-dive-coroutines/
https://blog.mindorks.com/what-are-coroutines-in-kotlin-bf4fecd476e9
Я считаю, что эта ссылка довольно проста. Ни один из этих ответов не пытается объяснить параллелизм и параллелизм, за исключением последнего пункта в этом ответе.
- что такое параллельная (программа)?
цитируется из программирования на Erlang Джо Армстронга, легендарного:
параллельная программа может работать потенциально быстрее на параллельном компьютере.
параллельная программа - это программа, написанная на языке параллельного программирования. Мы пишем параллельные программы из соображений производительности, масштабируемости или отказоустойчивости.
язык параллельного программирования - это язык, который имеет явные языковые конструкции для написания параллельных программ. Эти конструкции являются неотъемлемой частью языка программирования и ведут себя одинаково во всех операционных системах.
Параллельный компьютер - это компьютер, который имеет несколько процессоров (ЦП или ядер), которые могут работать одновременно.
Таким образом, параллелизм - это не то же самое, что параллелизм. Вы по-прежнему можете писать параллельные программы на одноядерном компьютере. Планировщик с разделением времени заставит вас почувствовать, что ваша программа работает одновременно.
Параллельная программа может работать параллельно на параллельном компьютере, но не гарантируется. ОС может дать вам только одно ядро для запуска вашей программы.
Следовательно, параллелизм - это программная модель параллельной программы, которая не означает, что ваша программа может работать параллельно физически.
- сопрограмма и параллелизм
Слово «сопрограмма» состоит из двух слов: «ко» (кооперативная) и «подпрограммы» (функции).
а. достигается ли параллелизм или параллелизм?
Для простоты давайте обсудим это на одноядерном компьютере.
Параллелизм достигается за счет таймшера из ОС. Поток выполняет свой код в назначенные ему временные рамки на ядре ЦП. Может быть выгружен ОС. Это также может передать управление ОС.
С другой стороны, сопрограмма передает управление другой сопрограмме в потоке, а не ОС. Таким образом, все сопрограммы в потоке по-прежнему используют временные рамки для этого потока, не уступая ядро ЦП другим потокам, управляемым ОС.
Таким образом, вы можете подумать о том, что сопрограмма обеспечивает разделение времени пользователем, а не ОС (или квазипараллелизмом). Сопрограммы выполняются на том же ядре, которое назначено потоку, который запускает эти сопрограммы.
Достигает ли Coroutine параллелизма? Если это код, привязанный к процессору, нет. Как и в случае с разделением времени, вы чувствуете, что они работают параллельно, но их выполнение чередуется, а не перекрывается. Если он привязан к вводу-выводу, да, он достигает параллельности аппаратно (устройства ввода-вывода), а не вашим кодом.
б. разница с вызовом функции?
Как показано на рисунке, для переключения управления не нужно вызывать return. Он может уступить без return. Сопрограмма сохраняет и делится состоянием в текущем функциональном фрейме (стеке). Таким образом, он намного легче, чем функция, поскольку вам не нужно сохранять регистры и локальные переменные в стек и перематывать стек вызовов, когда call ret.
С другой стороны, в python gevent библиотека - это сетевая библиотека на основе coroutine, которая дает вам поточные функции, такие как асинхронные сетевые запросы, без накладных расходов на создание и уничтожение потоков. Используемая coroutine библиотека greenlet.
Сопрограмма - это особый вид подпрограммы. В отличие от отношений главный-подчиненный между вызывающим и вызываемым подпрограммами, которые существуют с обычными подпрограммами, вызывающий и вызываемые сопрограммы более справедливы.
Сопрограмма - это подпрограмма, которая имеет несколько записей и сама контролирует их - поддерживается непосредственно в Lua.
Также называется симметричным управлением: вызывающий и вызываемые сопрограммы находятся на более равной основе.
Вызов сопрограммы называется резюме
Первое возобновление сопрограммы - это ее начало, но последующие вызовы входят в точку сразу после последнего выполненного оператора в сопрограмме.
Сопрограммы многократно возобновляют друг друга, возможно, навсегда
Сопрограммы обеспечивают квази-параллельное выполнение программных модулей (сопрограмм); их выполнение чередуется, но не перекрывается
Из Python Coroutine:
Выполнение сопрограмм Python можно приостанавливать и возобновлять во многих точках (см. Сопрограммы). Внутри тела функции сопрограммы идентификаторы await и async становятся зарезервированными ключевыми словами; Выражения await, async for и async with могут использоваться только в телах функций сопрограмм.
Сопрограмма - это функция, которая может приостанавливать выполнение, чтобы его возобновить позже. Сопрограммы не имеют стека: они приостанавливают выполнение, возвращаясь к вызывающей стороне. Это позволяет использовать последовательный код, который выполняется асинхронно (например, для обработки неблокирующего ввода-вывода без явных обратных вызовов), а также поддерживает алгоритмы для бесконечных последовательностей с ленивыми вычислениями и другие варианты использования.
Сравните с другим ответом:
На мой взгляд, часть возобновлено позже является основным отличием, как и @ 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)
Поскольку это параллелизм, он работает как многопоточность, особенно когда ожидание неизбежно (с точки зрения ОС), что также сбивает с толку.
Я буду расширять ответ @ user21714. Сопрограммы - это независимые пути выполнения, которые не могут выполняться одновременно. Они зависят от контроллера - например, библиотеки контроллеров python - для обработки переключения между этими путями. Но для этого сами сопрограммы должны вызывать yield или аналогичные структуры, которые позволяют приостанавливать их выполнение.
Вместо этого потоки работают на независимых вычислительных ресурсах и параллельно друг другу. Поскольку они находятся на разных ресурсах, нет необходимости вызывать yield, чтобы разрешить другие пути выполнения.
Вы можете увидеть этот эффект, запустив многопоточную программу - например, jvm приложение, в котором задействованы все восемь ваших core i7 гиперпоточных ядер: вы можете увидеть использование 797% в Activity Monitor или Top. Вместо этого при запуске типичной python программы - даже с coroutines или python threading - использование будет максимально на 100%. Т.е. одна машинная гиперпотока.
[Параллелизм против параллелизма]
Обычно нам нравится что-то вроде - сопрограммы - это легкие потоки, они позволяют нам писать асинхронный неблокирующий код синхронным образом.
Что касается 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 полностью зависит от реализации библиотеки.




yieldгенераторы в Python являются примером сопрограмм.asyncобъявляет, что это полноценная сопрограмма. - person Konrad Rudolph   schedule 13.10.2020switching between coroutines need not involve any system calls or any blocking calls whatsoever, сопрограмма должна быть легкой. Не могли бы вы прояснить это для меня? Потому что горутина создает потоки. То же самое и с lua? - person reyad   schedule 13.10.2020