我想知道是否有办法在函数中释放asyncio控件循环一段时间而不必使用coroutine装饰器和关键字的收益?
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)]))
我希望能够这样做,以便可以从对asyncio一无所知的代码调用do_something_periodically方法,但是会在睡眠期间释放循环控制。这可能吗?
谢谢!
已编辑以显示我的特定用例的缩减版
答案 0 :(得分:6)
这并不是asyncio
的工作方式。它使用显式异步模型 - 如果代码要将控制权返回给事件循环,则必须使用yield from
,否则必须使用回调/ Futures
。如果您在函数内部(例如do_something_periodically
),则无法使用yield from
2)完全退出该方法,无法将控制权返回给事件循环。您可以使用asyncio
和非asyncio
版本的类重复使用一些代码,但任何需要调用coroutine
的方法也必须是{ {1}}本身:
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)
逻辑:
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
完成,这意味着不需要更改代码。< / p>
答案 1 :(得分:0)
您可能需要查看at the solution that is used by the Motor library。基本上他们使用greenlets来“异步”同步代码。