Каковы варианты использования для сопрограммы? - PullRequest
44 голосов
/ 20 ноября 2008

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

Ответы [ 7 ]

48 голосов
/ 20 ноября 2008

Несколько хороших ответов, описывающих, что такое сопрограммы.

Но для фактического варианта использования. Возьми веб-сервер. У него несколько одновременных подключений, и он хочет запланировать чтение и запись всех из них.

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

21 голосов
/ 20 ноября 2008

Их много, например:

grep TODO *.c *.h | wc -l

Приведенный выше конвейер является в точности сопрограммой: команда grep генерирует последовательность строк, которые идут в буфер, команда wc "съедает их"; если буфер заполнен, grep «блокируется», пока буфер не опустеет, и если буфер пуст, команда wc ожидает нового ввода.

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

Если вы хотите больше посмотреть на них, посмотрите статьи в Википедии, особенно о сопрограммах и итераторах .

18 голосов
/ 26 сентября 2013

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

Чтобы поддерживать постоянную частоту кадров в игре, скажем, 60 кадров в секунду, у вас есть около 16,6 мсек для выполнения кода в каждом кадре. Сюда входит физическое моделирование, обработка ввода, рисование / рисование.

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

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

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

18 голосов
/ 20 ноября 2008

Истинные сопрограммы требуют поддержки вашего инструментария - они должны быть реализованы компилятором и поддерживаться базовой структурой.

Один реальный пример Coroutines найден с ключевым словом yield return, предоставленным в C # 2.0, который позволяет вам написать метод, который возвращает несколько значений для цикла.

Однако «возвращаемая доходность» имеет свои ограничения - реализация использует вспомогательный класс для захвата состояния и поддерживает только конкретный случай сопрограммы в качестве генератора (итератора).

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

11 голосов
/ 20 ноября 2008

Сопрограммы полезны для реализации шаблонов производителя / потребителя.

Например, Python представил сопрограммы в языковой функции под названием generators , которая была предназначена для упрощения реализации итераторов.

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

9 голосов
/ 14 июля 2010

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

Например, рассмотрим устройство, которое имеет пользовательский интерфейс с ЖК-дисплеем и модемом, и ему необходимо использовать модем для периодического вызова и отчета о своем состоянии независимо от того, что делает пользователь на клавиатуре. Самый хороший способ написания пользовательского интерфейса может заключаться в использовании таких функций, как "input_numeric_value (& CONV_SPEED_FORMAT, & transpor_speed);" которая будет возвращаться, когда пользователь ввел значение, и самый хороший способ обработки связи может быть использовать функции, такие как "wait_for_carrier ();" которая вернется, когда устройство либо подключится, либо определит, что не собирается.

Без сопрограмм либо подсистему пользовательского интерфейса, либо подсистему модема пришлось бы реализовывать с использованием конечного автомата. Использование сопрограмм позволяет писать обе подсистемы в наиболее естественном стиле. Обратите внимание, что важно, чтобы ни одна подсистема никогда не работала очень долго, не переводя вещи в «непротиворечивое» состояние и не вызывая yield (), и не вызывая yield (), не переводя вещи сначала в «непротиворечивое» состояние, но обычно это не сложно ограничения.

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

6 голосов
/ 04 февраля 2009

В качестве более конкретного примера в линии производитель / потребитель, что-то такое простое, как простая программа отчетов о партиях, может фактически использовать сопрограммы.

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

  • Легко организовать / понять код на стороне ввода, если вы можете "испускать" единицы работы в разных местах.
  • Также легко организовать / понять код выходной стороны, если он может "захватить" следующую единицу работы во вложенной структуре управления.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...