Этот код довольно странный способ использования await
. Большая часть кода, который использует await
, не взаимодействует с реализацией сопрограммы так же напрямую, как этот код.
Python сопрограммы реализованы поверх старого механизма итератора и генератора, с небольшим дополнительные меры предосторожности, чтобы не перепутать их. get
работает как генератор, а await f
работает как yield from f.__await__()
, если бы f
был генератором. Поскольку f.__await__
реализован как yield self
, await f
ведет себя как yield f
. (Не пытайтесь заменить await f
каким-либо видом yield
- вручную yield
ing не работает так же, как в сопрограмме.)
Код, который вы просматриваете, охватывает все get
сопрограмм в объекте Task
, а Task.step
выглядит следующим образом:
def step(self):
try:
f = self.coro.send(None)
except StopIteration:
return
f.callback = self.step
f = self.coro.send(None)
продвигает сопрограмму до тех пор, пока она не даст Future, и назначит Future f
. f.callback = self.step
устанавливает будущий обратный вызов, который будет вызываться с future.resolve()
позже.
get
вызывает selector.register(s.fileno(), EVENT_READ, f)
. Это регистрирует указанный файл с помощью селектора, поэтому, когда файл станет готовым к чтению, вывод selector.select()
будет включать SelectorKey
, указывающий этот факт. Любой объект, переданный в качестве третьего register
аргумента, будет присоединен к SelectorKey
, поэтому здесь Будущее будет прикреплено к SelectorKey
.
В следующем l oop:
while n_jobs:
events = selector.select()
for key, mask in events:
future = key.data
future.resolve()
events = selector.select()
ждет, пока любой из зарегистрированных файлов будет доступен для чтения. future = key.data
извлекает связанное Future из SelectorKey
, а future.resolve()
вызывает Task.step
, который продвигает ассоциированную сопрограмму до тех пор, пока не вернется снова или не завершится.