这不是asyncio
工作方式。它使用显式异步模型——如果代码要将控制权返回给事件循环,它要么必须使用yield from
,要么必须使用回调/ Futures
。如果你在一个函数内部(比如do_something_periodically
),你不能在没有 1) 使用yield from
2) 完全退出方法的情况下将控制权返回给事件循环。asyncio
您可以对类的版本和非版本进行一些代码重用asyncio
,但是任何需要调用 a 的方法也coroutine
必须是 acoroutine
本身:
class MyClass(object):
def do_something_periodically(self, delay, repeats):
for i in range(repeats):
self.do_something_useful()
self._sleep(delay)
def _sleep(self, delay):
time.sleep(delay)
def do_something_useful(self):
# Do something useful here, which doesn't need to yield to the event loop
class MyAsyncioClass(MyClass):
@asyncio.coroutine
def do_something_periodically(self, delay, repeats):
for i in range(repeats):
self.do_something_useful()
yield from self._sleep(delay)
@asyncio.coroutine
def _sleep(self, delay):
yield from asyncio.sleep(delay)
也就是说,看起来您的特定用例可能会以另一种方式解决,但它看起来有点难看,并且需要更改MyClass
逻辑:
class MyClass(object):
def do_something_periodically(self, delay, repeats, i=0):
while i < repeats:
# do something useful
if not self._sleep(delay, repeats, i):
break
i+= 1
return i
def _sleep(self, delay, repeats, i):
time.sleep(delay)
return True
class MyAsyncioClass(MyClass):
def do_something_periodically(self, delay, repeats, i=0):
out = super().do_something_periodically(delay, repeats, i)
if out == repeats:
asyncio.get_event_loop().stop()
def _sleep(self, delay, repeats, i):
i+=1
asyncio.get_event_loop().call_later(delay,
self.do_something_periodically,
delay, repeats, i)
return False
我们使用, 和调整来支持在正常用例的循环中完全迭代,但也可以在这种情况下以递增的loop.call_later
值重复调用。asyncio.sleep
do_something_periodically
while
i
asyncio
不幸的是,没有简单、可靠的方法可以为同步和asyncio
用例重用相同的代码。这是显式异步框架的主要缺点之一,例如asyncio
/tornado
与类似的东西gevent
,它使用隐式异步模型。使用gevent
,使用将控制权交还给事件循环time.sleep(delay)
的版本进行修补,直到完成,这意味着不需要更改代码。gevent
sleep