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)
inhello\u world
已到达。程序休眠一秒钟Hello World
已打印hello\u world
晚上好
晚上好
已打印时间。在晚上好
中睡眠(1)
。程序休眠一秒钟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()