翻译的python官方文档html
这个问题的恶心之处在于,若是你要理解coroutine
,你应该理解future
和task
。而你若是想理解future
和task
你应该先理解coroutine
。因此在第一遍阅读官方文档的时候,感受彻底是在梦游。但读到第二遍和第三遍的时候,就清楚不少了。python
协程(coroutine
)包括两个概念:git
async def
或者 @asyncio.coroutine
)协程功能:github
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
获取。调用协程函数并不能使该协程运行。调用协程函数所返回的协程对象,在被你安排执行以前,不会作任何事情。有两种方式能够启动它:express
await coroutine
或者yield from coroutine
ensure_task()
以及loop.create_task()
安排协程的执行。只有事件循环在运行的时候,协程才能运行api
在本文档中,有些普通函数返回了一个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.pyapp
# 这段代码和上面的代码执行结果是相同的。只不过用了另外一种调用协程的方式 # 先在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)
协程实际上是在不停返回结果的。最后的结果才会被返回。less
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!')一行,这个程序将永远不会结束。
Schedule the execution of a coroutine: wrap it in a future. Task is a subclass of Future.
将一个协程的执行过程安排好:用一个future
包装起来。Task
是Future
的一个子类。
A task is responsible for executing a coroutine object in an event loop. If the wrapped coroutine yields from a future, the task suspends the execution of the wrapped coroutine and waits for the completion of the future. When the future is done, the execution of the wrapped coroutine restarts with the result or the exception of the future.
Task
负责在实现循环中执行一个协程。 若是被包装的协程由一个future
产生,task
会暂停被包装协程的执行,等待future
的完成。当future
完成时,被包装协程会重启,当future
结果/异常返回。
Event loops use cooperative scheduling: an event loop only runs one task at a time. Other tasks may run in parallel if other event loops are running in different threads. While a task waits for the completion of a future, the event loop executes a new task.
事件循环使用协同调度:事件循环每次只能执行1个操做。其余task
能够在别的线程的事件循环中执行。当task
等待future
完成时,事件循环会执行一个新的task
。
The cancellation of a task is different from the cancelation of a future. Calling cancel() will throw a CancelledError to the wrapped coroutine. cancelled() only returns True if the wrapped coroutine did not catch the CancelledError exception, or raised a CancelledError exception.
取消task
与取消future
不一样。调用cancel()
将会向被包装的协程抛出CacelledError
。若是被包装协程没有捕获CacelledError
或者抛出CancelledError
时, cancelled()
才返回True
这里能够参考Task
源码中的一段注释:
Request that this task cancel itself.
This arranges for a CancelledError to be thrown into the wrapped coroutine on the next cycle through the event loop. The coroutine then has a chance to clean up or even deny the request using try/except/finally. Unlike Future.cancel, this does not guarantee that the task will be cancelled: the exception might be caught and acted upon, delaying cancellation of the task or preventing cancellation completely. The task may also return a value or raise a different exception. Immediately after this method is called, Task.cancelled() will not return True (unless the task was already cancelled). A task will be marked as cancelled when the wrapped coroutine terminates with a CancelledError exception (even if cancel() was not called)
太长了,我就不翻译了大意就是说,虽然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函数,注意,是能够返回结果的
一些参考资料
awesome asyncio
线程是操做系统层面的“并行”, 协程是应用程序层面的“并行”。
协程本质上就是:提供一个环境,保存一些须要等待的任务,当这些任务能够执行(等待结束)的时候,可以执行。再等待的过程当中,程序能够执行别的任务。
如下内容参考自:PYTHON: GENERATORS, COROUTINES, NATIVE COROUTINES AND ASYNC/AWAIT
@asyncio.coroutine def foo(): yield from ....
async def foo(): await ......
注意在@asyncio.coroutine
里只能是 yield from
, 在async
中,只能是await
。
你能够经过@type.coroutine
装饰器,降一个generator
变为一个可await
得协程。\
多线程:建立多个线程,每一个线程处理一个任务。会竞争资源、死锁什么的。CPU负责切换线程、保存恢复context。
Asnycio的文档,可是感受写的通常,有些语焉不详。
引用了一片关于线程的文章,还没看
不用gevent
的缘由,是由于gevent
仍是使用了线程,而线程是难以调试的。
Some thoughts on asynchronous API design in a post-async/await world