Tasks and coroutines
翻译的python官方文档
这个问题的恶心之处在于,如果你要理解coroutine
,你应该理解future
和task
。而你如果想理解future
和task
你应该先理解coroutine
。所以在第一遍阅读官方文档的时候,感觉完全是在梦游。但读到第二遍和第三遍的时候,就清楚很多了。
Coroutines
协程(coroutine
)包括两个概念:
- 协程函数(
async def
或者@asyncio.coroutine
) - 协程函数所返回的协程对象。
协程功能:
- 通过
result = await future
或者result = yeild from future
,悬挂协程,直到future
完成,获取future
的结果/异常(参见下面对future
及future
结果的描述,或等看完future
之后回来再阅读这一段)。 - 通过
result = await coroutine
或者result = yeild from coroutine
等待另一个协程的结果(或者异常,异常会被传播)。 returen expression
返回该协程的结果,被await
,或者yield from
获取。raise exception
,抛出异常,被await
,或者yield from
获取。
调用协程函数并不能使该协程运行。调用协程函数所返回的协程对象,在被你安排执行之前,不会做任何事情。有两种方式可以启动它:
- 通过在一个已经启动的协程中调用:
await coroutine
或者yield from coroutine
- 或者通过
ensure_task()
以及loop.create_task()
安排协程的执行。
只有事件循环在运行的时候,协程才能运行
在本文档中,有些普通函数返回了一个
future
,也被标记为coroutine
。这是故意的,这样以后就可以自由使用这些函数。如果是在回调代码中使用这个函数,用ensure_future
包装他。
hello_world.py
import asyncio # 创建一个协程 async def hello_world(): print("Hello World!") loop = asyncio.get_event_loop() # Blocking call which returns when the hello_world() coroutine is done # 在事件循环中调用这个协程 # 不过这里只有一个协程,而其不阻塞 loop.run_until_complete(hello_world()) loop.close()
hello_world2.py
# 这段代码和上面的代码执行结果是相同的。只不过用了另一种调用协程的方式 # 先在loop.call_soon()中安排好,再通过loop.run_forever()调用 # 注意,这里在hello_world中,调用了loop.stop(),否则事件循环就不会终止。 import asyncio def hello_world(loop): print('Hello World') loop.stop() loop = asyncio.get_event_loop() # Schedule a call to hello_world() loop.call_soon(hello_world, loop) # Blocking call interrupted by loop.stop() loop.run_forever() loop.close()
注意这里return 1+2
,实际上是raise StopIteration(3)
协程其实是在不停返回结果的。最后的结果才会被返回。
future
future
是一个容器,或者占位符(placeholder),用于接受异步的结果。这里指的是asyncio.Future
而不是coroutines.futures.Future
。
接口
result()
返回future的结果
set_result()
指示future已结束,并赋值。注意,必须显式地调用这个接口,才能给future赋值。
import asyncio # 一个对future进行赋值的函数 async def slow_operation(future): await asyncio.sleep(1) # 给future赋值 future.set_result('Future is done!') loop = asyncio.get_event_loop() # 创建一个future future1 = asyncio.Future() # 使用ensure_future 创建Task asyncio.ensure_future(slow_operation(future1)) future2 = asyncio.Future() asyncio.ensure_future(slow_operation(future2)) # gather Tasks,并通过run_uniti_complete来启动、终止loop loop.run_until_complete(asyncio.gather(future1, future2)) print(future1.result()) print(future2.result()) loop.close()
如果我们注释掉`future.set_result('Future is done!')一行,这个程序将永远不会结束。
TASK
将一个协程的执行过程安排好:用一个future
包装起来。Task
是Future
的一个子类。
Task
负责在实现循环中执行一个协程。 如果被包装的协程由一个future
产生,task
会暂停被包装协程的执行,等待future
的完成。当future
完成时,被包装协程会重启,当future
结果/异常返回。
事件循环使用协同调度:事件循环每次只能执行1个操作。其他task
可以在别的线程的事件循环中执行。当task
等待future
完成时,事件循环会执行一个新的task
。
取消task
与取消future
不同。调用cancel()
将会向被包装的协程抛出CacelledError
。如果被包装协程没有捕获CacelledError
或者抛出CancelledError
时, cancelled()
才返回True
太长了,我就不翻译了大意就是说,虽然task
的cancel()
函数,只会向被包装协程发出抛出一个异常,但是task
是否真的canceled
取决于被包装协程如何处理这个异常。
不要直接创建task
实例,使用ensure_future()
函数或者loop.create_task()
方法。
任务相关函数
asyncio.ensure_future
安排协程的执行。用future包装它,返回一个task。
asyncio.gather(*coros_or_futures, loop=None, return_exceptions=False)
将多个协程或future,集成为一个future。
所有的future必须在一个事件循环中。如果所有的future都成功完成了,则按照输入顺序(而不是返回顺序)返回所有result。
asyncio.sleep(delay, result=None, *, loop=None)
sleep函数,注意,是可以返回结果的
本文来自博客园,作者:孙龙-程序员,转载请注明原文链接:https://www.cnblogs.com/sunlong88/articles/9534523.html