为了防止上下文切换,我想创建一个大循环来为网络连接和一些例程提供服务。
这是正常功能的实现:
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循环。我怎样才能像普通的一样?即当它完成后,在给定的延迟时间后调用自己,但不只是在那里放一个循环。
答案 0 :(得分:18)
如果你真的想从协同程序中消除while循环(我不确定为什么你认为这是必要的;它是最自然的方式来做你自己的'重新尝试),您可以使用asyncio.async
(或Python {3.4}以上的asyncio.ensure_future
)来安排协程在下一个事件循环迭代中再次运行:
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()
请注意,如果您这样做,则必须切换回使用loop.run_forever()
,因为hello_world
/ good_evening
将在立即打印后立即退出。
答案 1 :(得分:3)
# 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()
答案 2 :(得分:1)
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没有尾调用优化。将代码留在这里作为一个错误的例子。
答案 3 :(得分:0)
你真的试着运行你给出的三个例子吗?行为上的差异非常明显。
既然你从来没有说过你的期望,那就说不出什么是正确的,什么不是。所有这三种实现都可能是对或错。我可以告诉你每个实现有什么行为,以及它为什么会有这样的行为;只有你知道它是否正确。
在第二个示例(yield from asyncio.sleep(1)
)中,两个协同程序同时运行。这意味着每个人都会自己执行; hello_world
每秒打印Hello World
,good_evening
每秒打印Good Evening
。
另外两个例子都使用阻塞的time.sleep(1)
。这意味着当第一个函数(无论是哪个;假设它是hello_world
)到达time.sleep(1)
时,整个程序将挂起一秒。这意味着当hello_world
睡眠时,good_evening
也无法运行,反之亦然。
程序执行如下:
hello_world
。time.sleep(1)
中的hello_world
。该程序休眠一秒钟。Hello World
已打印。hello_world
收益。good_evening
。Good Evening
已打印。time.sleep(1)
中的good_evening
。该程序休眠一秒钟。good_evening
收益。因此,每{em>} 秒出现Hello World
和Good Evening
,因为每个time.sleep(1)
之间有两次print
次调用。你很容易注意到,如果你运行这两个例子。