asyncio:是否可以在不使用yield的情况下释放对事件循环的控制?

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方法,但会在休眠期间释放循环控制.这可能吗?

谢谢!

编辑显示我的特定用例的缩减版本

dan*_*ano 6

这不是多么asyncio有效.它使用显式异步模型 - 如果代码要将控制权返回给事件循环,则必须使用yield from,或者必须使用回调/ Futures.如果你在一个函数内部(比如do_something_periodically),你就不能在没有1)的情况下将控制权返回给事件循环使用yield from2)完全退出该方法.您可以使用您的类的asyncioasyncio版本重复使用一些代码,但是任何需要调用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循环的正常使用情况,而且还具有增加值一再呼吁iasyncio情况.

不幸的是,没有简单,可靠的方法来为同步和asyncio用例重用相同的代码.这是显式异步框架的主要缺点之一,例如asyncio/ tornado与类似的东西gevent,它使用隐式异步模型.使用gevent,time.sleep(delay)修补一个gevent将控制权交还给事件循环的版本,直到sleep完成,这意味着不需要更改代码.