• en
  • Language: ru
  • Documentation version: latest

25. Корутины

Coroutines похожи на генераторы с некоторыми отличиями. Основными отличиями являются:

  • генераторы являются производителями данных

  • Корутины являются потребителями данных

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

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b

Затем мы обычно используем его в цикле for следующим образом:

for i in fib():
    print(i)

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

def grep(pattern):
    print("Searching for", pattern)
    while True:
        line = (yield)
        if pattern in line:
            print(line)

Подождите! Что возвращает yield? Ну, мы превратили его в корутину. Изначально она не содержит никаких значений, вместо этого мы предоставляем ей значения извне. Мы предоставляем значения с помощью метода .send(). Вот пример:

search = grep('coroutine')
next(search)
# Output: Searching for coroutine
search.send("I love you")
search.send("Don't you love me?")
search.send("I love coroutines instead!")
# Output: I love coroutines instead!

Доступ к отправленным значениям осуществляется с помощью yield. Почему мы запустили next()? Это необходимо для того, чтобы запустить корутину. Как и generators, корутины не запускают функцию немедленно. Вместо этого они запускают ее в ответ на методы __next__() и .send(). Поэтому необходимо выполнить next(), чтобы выполнение продвинулось до выражения yield.

Мы можем закрыть корутину, вызвав метод .close():

search = grep('coroutine')
# ...
search.close()

В coroutines есть еще много интересного. Я предлагаю вам ознакомиться с this awesome presentation Дэвида Бизли.