我正在尝试了解 python asyncio。
from datetime import datetime
import asyncio
def print_time(number, loop):
et = loop.time() + 10.0
while True:
print('loop {} time {}'.format(number, datetime.now()))
if (loop.time() >= et):
break
yield from asyncio.sleep(3)
loop = asyncio.get_event_loop()
asyncio.ensure_future(print_time(1,loop))
asyncio.ensure_future(print_time(2,loop))
loop.run_forever()
输出(来自 Jupyter 笔记本)
loop 1 time 2017-06-11 21:38:47.398280
loop 2 time 2017-06-11 21:38:47.398452
loop 1 time 2017-06-11 21:38:50.401818
loop 2 time 2017-06-11 21:38:50.402335
loop 1 time 2017-06-11 21:38:53.405770
loop 2 time 2017-06-11 21:38:53.406243
loop 1 time 2017-06-11 21:38:56.409524
loop 2 time 2017-06-11 21:38:56.410034
loop 1 time 2017-06-11 21:38:59.413300
loop 2 time 2017-06-11 21:38:59.413846
我对上述程序有以下疑问
在这种情况下,函数
print_time
被视为协程(如包含yield
语句?ensure_future() 每次调用时都会创建一个单独的任务/进程吗?从这个意义上说,它类似于 fork()
当前循环将永远运行。比如说 10 次迭代后,如何优雅地退出?
最佳答案
- In this case is the function print_time considered a coroutine (as in contains yield statement?
您可以在需要时从函数创建协程(例如,如果它应该等待另一个协程)。至create协程你应该使用特殊的装饰器 @asyncio.coroutine
(或者在 Python 3.5+ 中使用 async def
定义协程):
@asyncio.coroutine
def print_time(number, loop):
...
在您的情况下,生成器被视为协程,只是因为 asyncio 的协程是使用生成器实现的。您不应使用常规生成器作为协程,而应始终显式使用装饰器 @asyncio.coroutine
(或 async def
)来创建协程。
- does ensure_future() creates a separate task/process each time it is called? In that sense is it analogous to fork()
ensure_future
不会创建操作系统线程或进程。通常,所有协程/任务都在单个操作系统线程、单个进程中运行。
ensure_future
是一种规则异步脚本执行流程的方法。当您只是等待某个协程时,它下面的代码只有在协程完成后才会运行。 ensure_future
允许您"run coroutine in background"而不阻止其下面的代码执行。
示例1:
yield from coro_1()
yield from coro_2() # this line would be started only after coro_1 finished.
示例2:
asyncio.ensure_future(coro_1())
yield from coro_2() # this line would be started immediately.
# coro_1 and coro_2 would de facto run parallely.
- The current loop is running for ever. How do I gracefully exit after say 10 iterations.?
您有多种方法可以做到这一点,具体取决于您希望代码如何工作。
例如,这是一个:
from datetime import datetime
import asyncio
# We should somehow limit number of iterations for this coroutine.
# For example we can pass it as param 'tries':
@asyncio.coroutine
def print_time(number, loop, tries):
et = loop.time() + 10.0
for _ in range(tries):
print('loop {} time {}'.format(number, datetime.now()))
if (loop.time() >= et):
break
yield from asyncio.sleep(3)
@asyncio.coroutine
def main():
# Run to tasks parallely and await both done using 'asyncio.gather':
yield from asyncio.gather(
asyncio.ensure_future(print_time(1, loop, tries=5)),
asyncio.ensure_future(print_time(2, loop, tries=5))
)
loop = asyncio.get_event_loop()
# Use 'run_until_complete' to finish execution when some coroutine is done:
loop.run_until_complete(main())
输出:
loop 1 time 2017-06-11 15:16:03.864059
loop 2 time 2017-06-11 15:16:03.864059
loop 1 time 2017-06-11 15:16:06.864826
loop 2 time 2017-06-11 15:16:06.864826
loop 1 time 2017-06-11 15:16:09.865046
loop 2 time 2017-06-11 15:16:09.865046
loop 1 time 2017-06-11 15:16:12.865199
loop 2 time 2017-06-11 15:16:12.865199
loop 1 time 2017-06-11 15:16:15.865978
loop 2 time 2017-06-11 15:16:15.865978
[Finished in 12.2s]
关于python - 关于 asyncio 的说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44482416/