协程,又称为微线程,看上去像是子程序,可是它和子程序又不太同样,它在执行的过程当中,能够在中断当前的子程序后去执行别的子程序,再返回来执行以前的子程序,可是它的相关信息仍是以前的。html
优势:python
- 极高的执行效率,由于子程序切换而不是线程切换,没有了线程切换的开销;
- 不须要多线程的锁机制,由于只有一个线程在执行;
若是要充分利用CPU多核,能够经过使用多进程+协程的方式web
打开asyncio的源代码,能够发现asyncio中的须要用到的文件以下:数组

下面的则是接下来要总结的文件多线程
文件 |
解释 |
base_events |
基础的事件,提供了BaseEventLoop事件 |
coroutines |
提供了封装成协程的类 |
events |
提供了事件的抽象类,好比BaseEventLoop继承了AbstractEventLoop |
futures |
提供了Future类 |
tasks |
提供了Task类和相关的方法 |
函数 |
解释 |
coroutine(func) |
为函数加上装饰器 |
iscoroutinefunction(func) |
判断函数是否使用了装饰器 |
iscoroutine(obj) |
判断该对象是不是装饰器 |
若是在函数使用了coroutine
装饰器,就能够经过yield from
去调用async def
声明的函数,若是已经使用async def
声明,就没有必要再使用装饰器了,这两个功能是同样的。app
import asyncio
@asyncio.coroutine
def hello_world():
print("Hello World!")
async def hello_world2():
print("Hello World2!")
print('------hello_world------')
print(asyncio.iscoroutinefunction(hello_world))
print('------hello_world2------')
print(asyncio.iscoroutinefunction(hello_world2))
print('------event loop------')
loop = asyncio.get_event_loop()
# 一直阻塞该函数调用到函数返回
loop.run_until_complete(hello_world())
loop.run_until_complete(hello_world2())
loop.close()
上面的代码分别使用到了coroutine
装饰器和async def
,其运行结果以下:异步
------hello_world------True------hello_world2------True------event loop------Hello World!Hello World2!async
注意:不能够直接调用协程,须要一个event loop
去调用。ide
若是想要在一个函数中去获得另一个函数的结果,能够使用yield from
或者await
,例子以下:函数
import asyncio
async def compute(x, y):
print("Compute %s + %s ..." % (x, y))
await asyncio.sleep(1.0)
return x + y
async def print_sum(x, y):
result = await compute(x, y)
print("%s + %s = %s" % (x, y, result))
loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()
函数print_sum
会一直等到函数compute
返回结果,执行过程以下:

这个文件里面漏出来的只有BaseEventLoop
一个类,它的相关方法以下:
函数 |
解释 |
create_future() |
建立一个future对象而且绑定到事件上 |
create_task() |
建立一个任务 |
run_forever() |
除非调用stop,不然事件会一直运行下去 |
run_until_complete(future) |
直到future对象执行完毕,事件才中止 |
stop() |
中止事件 |
close() |
关闭事件 |
is_closed() |
判断事件是否关闭 |
time() |
返回事件运行时的时间 |
call_later(delay, callback, *args) |
设置一个回调函数,而且能够设置延迟的时间 |
call_at(when, callback, *args) |
同上,可是设置的是绝对时间 |
call_soon(callback, *args) |
立刻调用 |
函数 |
解释 |
get_event_loop() |
返回一个异步的事件 |
... |
... |
返回的就是BaseEventLoop的对象。
Future类的相关方法以下:
方法 |
解释 |
cancel() |
取消掉future对象 |
cancelled() |
返回是否已经取消掉 |
done() |
若是future已经完成则返回true |
result() |
返回future执行的结果 |
exception() |
返回在future中设置了的exception |
add_done_callback(fn) |
当future执行时执行回调函数 |
remove_done_callback(fn) |
删除future的全部回调函数 |
set_result(result) |
设置future的结果 |
set_exception(exception) |
设置future的异常 |
设置future的例子以下:
import asyncio
async def slow_operation(future):
await asyncio.sleep(1) # 睡眠
future.set_result('Future is done!') # future设置结果
loop = asyncio.get_event_loop()
future = asyncio.Future() # 建立future对象
asyncio.ensure_future(slow_operation(future)) # 建立任务
loop.run_until_complete(future) # 阻塞直到future执行完才中止事件
print(future.result())
loop.close()
run_until_complete
方法在内部经过调用了future的add_done_callback
,当执行future完毕的时候,就会通知事件。
下面这个例子则是经过使用future的add_done_callback
方法实现和上面例子同样的效果:
import asyncio
async def slow_operation(future):
await asyncio.sleep(1)
future.set_result('Future is done!')
def got_result(future):
print(future.result())
loop.stop() # 关闭事件
loop = asyncio.get_event_loop()
future = asyncio.Future()
asyncio.ensure_future(slow_operation(future))
future.add_done_callback(got_result) # future执行完毕就执行该回调
try:
loop.run_forever()
finally:
loop.close()
一旦slow_operation
函数执行完毕的时候,就会去执行got_result
函数,里面则调用了关闭事件,因此不用担忧事件会一直执行。
Task类是Future的一个子类,也就是Future中的方法,task均可以使用,类方法以下:
方法 |
解释 |
current_task(loop=None) |
返回指定事件中的任务,若是没有指定,则默认当前事件 |
all_tasks(loop=None) |
返回指定事件中的全部任务 |
cancel() |
取消任务 |
并行执行三个任务的例子:
import asyncio
async def factorial(name, number):
f = 1
for i in range(2, number+1):
print("Task %s: Compute factorial(%s)..." % (name, i))
await asyncio.sleep(1)
f *= i
print("Task %s: factorial(%s) = %s" % (name, number, f))
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(
factorial("A", 2),
factorial("B", 3),
factorial("C", 4),
))
loop.close()
执行结果为
Task A: Compute factorial(2)...Task B: Compute factorial(2)...Task C: Compute factorial(2)...Task A: factorial(2) = 2Task B: Compute factorial(3)...Task C: Compute factorial(3)...Task B: factorial(3) = 6Task C: Compute factorial(4)...Task C: factorial(4) = 24
能够发现,ABC同时执行,直到future执行完毕才退出。
下面一些方法是和task相关的方法
方法 |
解释 |
as_completed(fs, *, loop=None, timeout=None) |
返回是协程的迭代器 |
ensure_future(coro_or_future, *, loop=None) |
调度执行一个 coroutine object:而且它封装成future。返回任务对象 |
async(coro_or_future, *, loop=None) |
丢弃的方法,推荐使用ensure_future |
wrap_future(future, *, loop=None) |
Wrap a concurrent.futures.Future object in a Future object. |
gather(*coros_or_futures, loop=None, return_exceptions=False) |
从给定的协程或者future对象数组中返回future汇总的结果 |
sleep(delay, result=None, *, loop=None) |
建立一个在给定时间(以秒为单位)后完成的协程 |
shield(arg, *, loop=None) |
等待future,屏蔽future被取消 |
wait(futures, *, loop=None, timeout=None, return_when=ALL_COMPLETED) |
等待由序列futures给出的Futures和协程对象完成。协程将被包裹在任务中。返回含两个集合的Future:(done,pending) |
wait_for(fut, timeout, *, loop=None) |
等待单个Future或coroutine object完成超时。若是超时为None,则阻止直到future完成 |
参考文章
官方文档