Python 如何创建一个事件循环,并在其上永久运行滚动协同程序?

Python 如何创建一个事件循环,并在其上永久运行滚动协同程序?,python,python-3.x,asynchronous,coroutine,python-asyncio,Python,Python 3.x,Asynchronous,Coroutine,Python Asyncio,为了防止上下文切换,我想创建一个大循环来服务于网络连接和一些例程 以下是正常功能的实现: import asyncio import time def hello_world(loop): print('Hello World') loop.call_later(1, hello_world, loop) def good_evening(loop): print('Good Evening') loop.call_later(1, good_evening

为了防止上下文切换,我想创建一个大循环来服务于网络连接和一些例程

以下是正常功能的实现:

import asyncio
import time


def hello_world(loop):
    print('Hello World')
    loop.call_later(1, hello_world, loop)

def good_evening(loop):
    print('Good Evening')
    loop.call_later(1, good_evening, loop)

print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()

print('step: loop.call_soon(hello_world, loop)')
loop.call_soon(hello_world, loop)
print('step: loop.call_soon(good_evening, loop)')
loop.call_soon(good_evening, loop)

try:
    # Blocking call interrupted by loop.stop()
    print('step: loop.run_forever()')
    loop.run_forever()
except KeyboardInterrupt:
    pass
finally:
    print('step: loop.close()')
    loop.close()
以下是协同程序的实现:

import asyncio


@asyncio.coroutine
def hello_world():
    while True:
        yield from asyncio.sleep(1)
        print('Hello World')

@asyncio.coroutine
def good_evening():
    while True:
        yield from asyncio.sleep(1)
        print('Good Evening')

print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()
try:
    print('step: loop.run_until_complete()')
    loop.run_until_complete(asyncio.wait([
        hello_world(),
        good_evening()
    ]))
except KeyboardInterrupt:
    pass
finally:
    print('step: loop.close()')
    loop.close()
混合的一个:

import asyncio
import time


def hello_world(loop):
    print('Hello World')
    loop.call_later(1, hello_world, loop)

def good_evening(loop):
    print('Good Evening')
    loop.call_later(1, good_evening, loop)

@asyncio.coroutine
def hello_world_coroutine():
    while True:
        yield from asyncio.sleep(1)
        print('Hello World Coroutine')

@asyncio.coroutine
def good_evening_coroutine():
    while True:
        yield from asyncio.sleep(1)
        print('Good Evening Coroutine')

print('step: asyncio.get_event_loop()')
loop = asyncio.get_event_loop()

print('step: loop.call_soon(hello_world, loop)')
loop.call_soon(hello_world, loop)
print('step: loop.call_soon(good_evening, loop)')
loop.call_soon(good_evening, loop)
print('step: asyncio.async(hello_world_coroutine)')
asyncio.async(hello_world_coroutine())
print('step: asyncio.async(good_evening_coroutine)')
asyncio.async(good_evening_coroutine())

try:
    loop.run_forever()
except KeyboardInterrupt:
    pass
finally:
    print('step: loop.close()')
    loop.close()

如您所见,每个协程函数都有一个while循环。我怎样才能使它像正常的一样?也就是说,完成后,在给定的延迟时间后调用自身,但不只是在那里放一个循环。

您是否确实尝试运行您给出的三个示例?行为上的差异非常明显

既然你从来没有说过你所期望的,那就不知道什么是对的什么是错的。这三种实现可能是对的,也可能是错的。我可以告诉您每个实现都有什么行为,以及为什么会有这种行为;只有你知道它是否正确


在第二个示例中(
yield from asyncio.sleep(1)
),这两个协程同时运行。这意味着每个人都将自己执行
hello\u world
每秒打印
hello world
,而
good\u night
每秒打印
good night

另外两个示例都使用
time.sleep(1)
,这是阻塞。这意味着,当第一个函数(无论哪一个是;假设它是
hello\u world
)到达
time.sleep(1)
,整个程序将挂起一秒钟。这意味着当
hello\u world
睡眠时,
good\u night
也不能运行,反之亦然

程序的执行方式如下:

  • 进入循环
  • 循环调用
    hello\u world
  • time.sleep(1)
    in
    hello\u world
    已到达。程序休眠一秒钟
  • Hello World
    已打印
  • hello\u world
  • 循环调用
    晚上好
  • 晚上好
    已打印
  • 时间。在
    晚上好
    中睡眠(1)
    。程序休眠一秒钟
  • 晚上好
  • 去2号
  • 因此,
    Hello World
    goodnight
    每两秒钟都会出现一次,因为有两次
    时间。睡眠(1)
    在每次
    print
    之间调用。如果运行这两个示例,您将很容易注意到

    import asyncio
    
    
    @asyncio.coroutine
    def hello_world_coroutine():
        yield from asyncio.sleep(1)
        print('Hello World Coroutine')
        yield from hello_world_coroutine()
    
    @asyncio.coroutine
    def good_evening_coroutine():
        yield from asyncio.sleep(1)
        print('Good Evening Coroutine')
        yield from good_evening_coroutine()
    
    print('step: asyncio.get_event_loop()')
    loop = asyncio.get_event_loop()
    try:
        print('step: loop.run_until_complete()')
        loop.run_until_complete(asyncio.wait([
            hello_world_coroutine(),
            good_evening_coroutine()
        ]))
    except KeyboardInterrupt:
        pass
    finally:
        print('step: loop.close()')
        loop.close()
    
    UPD


    此代码将达到最大递归深度。可能是因为Python没有尾部调用优化。把这里的代码留作一个错误的例子。

    如果您真的想从协同程序中消除while循环(我不知道为什么您觉得这是必要的;这是您尝试做的事情最自然的方式),您可以使用(或者
    asyncio.sure\u future
    在Python 3.4.4+上)要计划在下一个事件循环迭代中再次运行协同路由,请执行以下操作:

    import asyncio
    
    @asyncio.coroutine
    def hello_world():
        yield from asyncio.sleep(1)
        print('Hello World')
        asyncio.async(hello_world())
    
    @asyncio.coroutine
    def good_evening():
        yield from asyncio.sleep(1)
        print('Good Evening')
        asyncio.async(good_evening())
    
    print('step: asyncio.get_event_loop()')
    loop = asyncio.get_event_loop()
    try:
        print('step: loop.run_until_complete()')
        asyncio.async(hello_world())
        asyncio.async(good_evening())
        loop.run_forever()
    except KeyboardInterrupt:
        pass
    finally:
        print('step: loop.close()')
        loop.close()
    

    请注意,如果您这样做,您必须切换回使用
    循环。请永远运行()
    ,因为
    hello\u world
    /
    晚上好
    将在打印后立即退出。

    谢谢@uranusjr。我写了代码并运行了它。我知道它的流程,也知道睡眠会阻止线程并从异步中产生。不我不确定的是这条路是正确的还是蟒蛇式的。我知道协同程序的概念,但以前从未使用过。到目前为止,我还没有看到其他人为此编写相同的代码。它们使用普通函数和协同程序中的一种,但不能同时使用两者;只有在使用异步API(如
    asyncio.sleep
    )时,程序才是异步的。您可以在协同程序中使用阻塞API(例如,
    time.sleep
    ),但阻塞API会阻塞整个程序,包括其他协同程序。是否可以接受取决于您的用例。再次感谢您。我已经更新了问题和代码。将call_soon替换为call_later,并删除time.sleep()。更新的示例对我很有意义。现在,示例1和示例2的行为应该相同,示例3也确实是异步的。但我想知道的是如何发出while循环,我不会马上把它作为答案。等待一段时间,等待更好的解决方案。这实际上是行不通的-最终你将达到最大递归深度,程序将崩溃。为什么你不喜欢循环?带循环的代码非常简单易读,这就是我想要的。非常感谢。看起来好多了。谢谢你,莫顿。使用Python3.6.1测试该代码。尽管由于等待,最终会耗尽堆栈帧。最好
    等待asyncio.sleep(1.0)
    将coros作为未来添加到事件循环中。
    # asyncio_coroutine_forever.py
    
    import asyncio
    
    async def hello_world():
    
        await asyncio.sleep(1)
        print('Hello World')
        await good_evening()
    
    
    async def good_evening():
    
        await asyncio.sleep(1)
        print('Good Evening')
        await hello_world()
    
    
    loop = asyncio.get_event_loop()
    
    try:
    
        loop.run_until_complete(hello_world())
        loop.run_until_complete(good_evening())
        loop.run_forever()
    
    finally:
    
        print('closing event loop')
        loop.close()