正文
()
形参watcher就是loop.timer实例,其cython描述在corecext.pyx,我们简单理解成是一个定时器事件就行了。上面的代码中,创建了一个Waiter(gevent.hub.Waiter)对象,这个对象起什么作用呢,这个类的doc写得非常清楚:
Waiter
.
__doc_
_
A
low level communication utility
for
greenlets
.
Waiter
is
a
wrapper around
greenlet
'
s
``
switch
()``
and
``
throw
()``
calls that makes them somewhat
safer
:
*
switching will occur only
if
the waiting greenlet
is
executing
:
meth
:
`
get
`
method
currently
;
*
any
error raised
in
the greenlet
is
handled
inside
:
meth
:
`
switch
`
and
:
meth
:
`
throw
`
*
if
:
meth
:
`
switch
`
/:
meth
:
`
throw
`
is
called before the receiver
calls
:
meth
:
`
get
`,
then
:
class
:
`
Waiter
`
will store the
value
/
exception
.
The
following
:
meth
:
`
get
`
will
return
the
value
/
raise
the exception
简而言之,是对greenlet.greenlet类switch 和 throw函数的分装,用来存储返回值greenlet的返回值或者捕获在greenlet中抛出的异常。我们知道,在原生的greenlet中,如果一个greenlet抛出了异常,那么该异常将会展开至其parent greenlet。
回到Hub.wait函数,第8行 watcher.start(waiter.switch, unique) 注册了一个回调,在一定时间(1s)之后调用回调函数waiter.switch。注意,waiter.switch此时并没有执行。然后第10行调用waiter.get。看看这个get函数(gevent.hub.Waiter.get):
def get
(
self
)
:
"""If a value/an exception is stored, return/raise it. Otherwise until switch() or throw() is called."""
if
self
.
_exception
is
not
_NONE
:
if
self
.
_exception
is
None
:
return
self
.
value
else
:
getcurrent
().
throw
(
*
self
.
_exception
)
else
:
if
self
.
greenlet
is
not
None
:
raise ConcurrentObjectUseError
(
'This Waiter is already used by %r'
%
(
self
.
greenlet
,
))
self
.
greenlet
=
getcurrent
()
# 存储当前协程,之后从hub switch回来的时候使用
try
:
return
self
.
hub
.
switch
()
# switch到hub
finally
:
self
.
greenlet
=
None
核心的逻辑在第11到15行,11行中,getcurrent获取当前的greenlet(在这个测试代码中,是main greenlet,即最原始的greenlet),将其复制给waiter.greenlet。然后13行switch到hub,在greenlet回顾章节的第二条提到,greenlet.greenlet的子类需要重写run方法,当调用子类的switch时会调用到该run方法。Hub的run方法实现如下:
def run
(
self
)
:
"""
Entry-point to running the loop. This method is called automatically
when the hub greenlet is scheduled; do not call it directly.