Bre*_*ire 1 python python-3.x python-asyncio
我想知道是否有任何方法在函数中释放asyncio控制循环一段时间而不必使用协程装饰器和关键字的收益?
import asyncio
import time
class MyClass(object):
def do_something_periodically(self, delay, repeats):
for i in range(repeats):
# Do something useful
self._sleep(delay)
def _sleep(self, delay):
time.sleep(delay)
class MyAsyncioClass(MyClass):
def _sleep(self, delay):
# Perform an asyncio.sleep(delay) here which yields control of the event loop
# and waits for time delay before returning
loop = asyncio.get_event_loop()
obj1 = MyAsyncioClass()
obj2 = MyAsyncioClass()
loop.run_until_complete(asyncio.wait(
[obj1.do_something_periodically(1000, 3),
obj2.do_something_periodically(2000, 2)]))
Run Code Online (Sandbox Code Playgroud)
我希望能够这样做,以便可以从对asyncio一无所知的代码调用do_something_periodically方法,但会在休眠期间释放循环控制.这可能吗?
谢谢!
编辑显示我的特定用例的缩减版本
这不是多么asyncio有效.它使用显式异步模型 - 如果代码要将控制权返回给事件循环,则必须使用yield from,或者必须使用回调/ Futures.如果你在一个函数内部(比如do_something_periodically),你就不能在没有1)的情况下将控制权返回给事件循环使用yield from2)完全退出该方法.您可以使用您的类的asyncio非asyncio版本重复使用一些代码,但是任何需要调用a的方法也coroutine必须是一个coroutine本身:
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)
Run Code Online (Sandbox Code Playgroud)
也就是说,看起来您的特定用例可能会以另一种方式解决,但它看起来很难看,并且需要更改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
Run Code Online (Sandbox Code Playgroud)
我们用loop.call_later做的等价asyncio.sleep,并调整do_something_periodically通过同时支持完全迭代while循环的正常使用情况,而且还具有增加值一再呼吁i的asyncio情况.
不幸的是,没有简单,可靠的方法来为同步和asyncio用例重用相同的代码.这是显式异步框架的主要缺点之一,例如asyncio/ tornado与类似的东西gevent,它使用隐式异步模型.使用gevent,time.sleep(delay)修补一个gevent将控制权交还给事件循环的版本,直到sleep完成,这意味着不需要更改代码.