Эта статья относится к:
выход и выход из
Сначала изучим или рассмотримyieldиyield fromиспользование. Если вы уверены, что завершили свое понимание, вы можете перейти к следующему разделу.
Python 3.3 предлагает новый синтаксис:yield from.
yield from iterator
По сути, это эквивалентно:
for x in iterator:
yield x
В следующем примере дваyield fromскладываются, и комбинация дает большоеiterable(пример изОфициальный сайт 3.3 релиз):
>>> def g(x):
... yield from range(x, 0, -1)
... yield from range(x)
...
>>> list(g(5))
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
пониматьyield fromВажно для следующей части. хочу полностью понятьyield from, давайте посмотрим на официальный пример:
def accumulate():
tally = 0
while 1:
next = yield
if next is None:
return tally
tally += next
def gather_tallies(tallies):
while 1:
tally = yield from accumulate()
tallies.append(tally)
tallies = []
acc = gather_tallies(tallies)
next(acc) # Ensure the accumulator is ready to accept values
for i in range(4):
acc.send(i)
acc.send(None) # Finish the first tally
for i in range(5):
acc.send(i)
acc.send(None) # Finish the second tally
print(tallies)
Я также специально для этого записал видео, вы можете посмотреть его с текстом, а можете открыть pycharm и любые средства отладки, чтобы отладить самостоятельно. ссылка на видео
Разбираемся вместе:
отacc = gather_tallies(tallies)Эта строка начинается сgather_talliesВ функции есть выход, поэтому она не будетwhile 1Выполняется немедленно (как видно из видео, акк — это тип генератора).
next(acc):
next() перейдет к следующему выходу или сообщит об ошибке StopIteration.
next(acc)Введите тело функции collect_tallies, оно есть в collect_tallies.yield from accumulate(), next(acc) не остановится на этом, а войдет в "подгенератор" аккумулировать, а затемnext = yieldгде, встретилyield, затем приостановите функцию и вернитесь.
for i in range(4):
acc.send(i)
пониматьacc.send(value)Какая польза:
- Шаг 1: Вернитесь туда, где вы остановились
- Шаг 2: Присвойте значение value
xxx = yieldсерединаxxx, в данном примере этоnext.
accumulateЦикл while в функции, судя поnextЗначение None определяет выход из цикла. существуетfor i in range(4)В этом цикле for ни i не равно None, поэтому цикл while не прерывается. Однако, согласно тому, что мы сказали ранее:next() перейдет к следующему месту выхода и остановится, этот цикл делает круг и снова встречаетсяyield, поэтому он приостанавливает функцию и возвращает управление основному потоку.
Для уточнения: для накопления его бесконечный цикл не закончен, и в следующий раз, когда он возобновит свою работу через next(), он все еще будет выполнять свой бесконечный цикл. Для collect_tallies его
yield from accumulate()Это еще не закончено. Для всей программы действительно существует несколько переходов между основным процессом и телом функции накопления.
Следующий взгляд на первыйacc.send(None): В настоящее времяnextЗначение переменной становитсяNone,if next is Noneусловие верно, то возвратtallyк предыдущей функции. (Посчитайте, получается 0 + 1 + 2 + 3 = 6). Это возвращаемое значение присваиваетсяgather_talliesсерединаgally. Здесь следует отметить, что,gather_talliesБесконечный цикл еще не закончился, так что звоните в это времяnext(acc)не будет сообщатьStopIterationОшибка.
for i in range(5):
acc.send(i)
acc.send(None) # Finish the second tally
Эта часть аналогична предыдущей логике. acc.send(i) войдет первымgather_tallies, затем введитеaccumulate, присвойте значениеnext.acc.send(None)Остановите петлю. Окончательный счет равен 10 (0 + 1 + 2 + 3 + 4).
Окончательный итоговый список таков:[6,10].
Краткая история развития Python async await
Взгляните на определение Coroutine в Википедии:
Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing execution to be suspended and resumed.
Дело в томby allowing execution to be suspended and resumed.(чтобы выполнение можно было приостановить и возобновить). С точки зрения непрофессионала, это:
сопрограммы — это функции, выполнение которых вы можете приостановить. (отHow the heck does async/await work in Python 3.5?)
Разве это не генератор?
python2.2 - происхождение генератора
Концепция генератора Python возникла в python2.2 (2001 г.), когда он был исключен.pep255,отЯзык программирования иконокВдохновленный.
Преимущество генераторов в том, что они не занимают место впустую, см. следующий пример:
def eager_range(up_to):
"""Create a list of integers, from 0 to up_to, exclusive."""
sequence = []
index = 0
while index < up_to:
sequence.append(index)
index += 1
return sequence
Если вы используете эту функцию для создания списка 10W, вам нужно дождаться завершения цикла while и возврата. тогда этоsequenceСписок займет 10W элементов пространства. Не говоря уже о трудоемкости (с точки зрения времени, когда список последовательностей можно использовать в первый раз), он занимает много места.
С помощью предыдущей частиyield, немного изменено:
def lazy_range(up_to):
"""Generator to return the sequence of integers from 0 to up_to, exclusive."""
index = 0
while index < up_to:
yield index
index += 1
Таким образом, ему нужно всего лишь занять пространство одного элемента, и диапазон можно использовать сразу, не дожидаясь его полной генерации.
python2.5 : send stuff back
Некоторые предусмотрительные старики думали,Если мы сможем воспользоваться тем фактом, что генераторы могут приостанавливаться, а затем найти способ добавить возможность отправлять данные обратно, разве это не будет соответствовать определению сопрограмм в Википедии?
Так что естьpep342.
Один упоминается в pep342send()метод, который позволяет нам отправить «материал» обратно в генератор и позволить ему работать. Рассмотрим следующий пример:
def jumping_range(up_to):
"""Generator for the sequence of integers from 0 to up_to, exclusive.
Sending a value into the generator will shift the sequence by that amount.
"""
index = 0
while index < up_to:
jump = yield index
if jump is None:
jump = 1
index += jump
if __name__ == '__main__':
iterator = jumping_range(5)
print(next(iterator)) # 0
print(iterator.send(2)) # 2
print(next(iterator)) # 3
print(iterator.send(-1)) # 2
for x in iterator:
print(x) # 3, 4
здесьsendОтправьте «материал» в генератор, назначьте его для перехода, а затем определите, является ли переход «Нет», чтобы выполнить соответствующую логику.
python3.3 yield from
Начиная с Python 2.5, до версии Python 3.3 в генераторы не вносилось никаких существенных улучшений.pep380. Это бодрящее предложение предлагаетyield fromЭто можно понимать как синтаксический сахар, что делает написание генераторов более лаконичным:
def lazy_range(up_to):
"""Generator to return the sequence of integers from 0 to up_to, exclusive."""
index = 0
def gratuitous_refactor():
nonlocal index
while index < up_to:
yield index
index += 1
yield from gratuitous_refactor()
Мы уже подробно говорили о yield from в первом разделе, поэтому здесь я не буду вдаваться в подробности.
асинхронный модуль python3.4
Межстраничное объявление: цикл событий (цикл событий)
Если у вас есть опыт программирования на js, вы должны кое-что знать о цикле обработки событий.
Чтобы понять концепцию, лучше всего покопаться в википедии:
цикл событий "является программной конструкцией, которая ожидает и отправляет события или сообщения в программе" - отEvent loop - wikipedia
Проще говоря, реализация цикла событийКогда произойдет событие А, выполните действие Б. Возьмем в качестве примера цикл событий JavaScript в браузере: вы нажимаете на что-то (происходит событие), оно запускает определенныйonclickфункция (выполняет операцию B).
В Python asyncio обеспечивает цикл обработки событий (вспомнимПример из предыдущего поста), асинциоглавныйОсновное внимание уделяется области сетевых запросов.«Происходит событие A» здесь в основном заключается в том, что сокет может быть записан и сокет может быть прочитан (черезselectorsмодуль).
К этому времени Python прошелConcurrent programmingФорма обладает силой асинхронного программирования.
Concurrent programmingВыполнять только в одном потоке. В блоге go language есть очень хорошее видео:Concurrency is not parallelism, это стоит посмотреть.
асинхронный код в эту эпоху
Асинхронный код для этого периода выглядит так:
import asyncio
# Borrowed from http://curio.readthedocs.org/en/latest/tutorial.html.
@asyncio.coroutine
def countdown(number, n):
while n > 0:
print('T-minus', n, '({})'.format(number))
yield from asyncio.sleep(1)
n -= 1
loop = asyncio.get_event_loop()
tasks = [
asyncio.ensure_future(countdown("A", 2)),
asyncio.ensure_future(countdown("B", 3))]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
Результат:
T-minus 2 (A)
T-minus 3 (B)
T-minus 1 (A)
T-minus 2 (B)
T-minus 1 (B)
На этот раз с помощьюasyncio.coroutineДекоратор, помечающий функцию, которую может использовать цикл обработки событий asyncio.
Видетьyield from asyncio.sleep(1)Пока что? Вызывая объект asyncio.Futureyield from, передать будущий объект в цикл событий, когда объект ожидает, что что-то произойдет (в этом примере, ожидая asyncio.sleep(1) через 1 с), приостановить функцию и начать делать другие вещи. Когда произойдет что-то, чего ожидает этот объект будущего, цикл обработки событий заметит это, а затем, вызвавsend()способ возобновить с того места, на котором он остановился.
разбить приведенный выше код:
Цикл событий открывает дваcountdown()Вызов сопрограммы, выполняется до тех пор, покаyield from asyncio.sleep(1), который возвращает будущий объект, затем приостанавливается, и цикл обработки событий продолжает отслеживать оба будущих объекта. Через 1 секунду цикл событий отправит () будущий объект сопрограмме, и сопрограмма продолжит работу, распечатываяT-minus 2 (A)Ждать.
python3.5 async await
питон3.4
@asyncio.coroutine
def py34_coro():
yield from stuff()
В Python 3.5 это можно выразить более кратким синтаксисом:
async def py35_coro():
await stuff()
Это изменение не имеет большого значения с точки зрения синтаксиса.Что действительно важно, так это повышенный философский статус сопрограмм в Python.До python3.4 асинхронные функции были скорее обычным маркером (декоратором), после этого сопрограммы стали базовым абстрактным базовым классом:class collections.abc.Coroutine.
How the heck does async/await work in Python 3.5?Также упоминается в статьеasync,awaitРеализация лежащего в основе байт-кода не будет подробно обсуждаться здесь, в конце концов, место ограничено.
Думайте об асинхронности и ожидании как об API, а не о реализации
Разработчик ядра Python (и один из моих любимых говорящих о pycon)David M. Beazleyна PyCon Brasil 2015эта речьупоминается в:мы должны положитьasyncиawaitРассматривайте это как API, а не как реализацию.Это,async,awaitне равноasyncio,asyncioпростоasync,awaitреализация . (конечноasyncioсделал возможным асинхронное программирование в Python 3.4, что подтолкнулоasync,awaitвнешний вид)
Он также открыл исходный код проектаGitHub.com/dab EA в/Промо..., базовый механизм цикла событий иasyncioРазные,asyncioиспользуетfuture object,curioиспользуетtuple. В то же время эти две библиотеки имеют разную направленность,asyncioпредставляет собой набор фреймворков,curioОн относительно более легкий, и сами пользователи должны учитывать больше вещей.
How the heck does async/await work in Python 3.5?Также в этой статье есть простой пример реализации событийного цикла, если интересно, можете посмотреть, а если есть время, то реализовать вместе.
в заключении
- Сопрограмма имеет только один поток.
- Операционная система планирует процессы и сопрограммы с помощью функций планирования цикла событий.
- async и await поднимают философский статус сопрограмм в Python на более высокий уровень.
Самое главное чувство: Ничто не является Волшебством. Теперь вы должны получить общее представление о сопрограммах Python.
Если вы действительно любите компьютерные науки, как и я, любите изучать лежащую в их основе логику, обратите внимание на мой общедоступный номер WeChat: