link:
高层级API
协程
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
task1 = asyncio.create_task(
say_after(1, 'hello'))
task2 = asyncio.create_task(
say_after(2, 'world'))
print(f"started at {time.strftime('%X')}")
# Wait until both tasks are completed (should take
# around 2 seconds.)
await task1
await task2
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
async
定义一个协程await
等待一个协程asyncio.create_task
创建一个task
以便后续并发执行作为任务的多个协程asyncio.run
运行一个协程
可等待对象
- 可以在
await
中使用的对象,主要有三种类型协程
、task
、future
- 协程函数:
async def
定义的函数, 协程对象: 调用协程函数所返回的对象 - 支持旧的
基于生成器的
协程 - 任务:
asyncio.create_task()
, 可以将一个协程函数包装成一个任务,该协程将自动排入日程准备立即运行 future
是一个低层级
可等待对象,表示一个异步操作的最终结果
, e.g.asyncio.gather()
loop.run_in_executor()
Task
是Future
子类
- 协程函数:
# 基于生成器的协程
@asyncio.coroutine
def old_style_coroutine():
yield from asyncio.sleep(1)
常用高层级API
运行
asyncio.run(coro, *, debug=False)
创建任务
asyncio.create_task(coro, *, name=None)
- 支持3.7+,
asyncio.ensure_future
支持所有python版本 - 将
coro
协程打包为一个Task
排入日程准备执行,即碰到await
之后即有机会运行 - 该任务会在
get_running_loop()
返回的事件循环中执行,如果当前线程没有在运行的循环则会引发RuntimeError
。
- 支持3.7+,
等待
coroutine asyncio.sleep(delay, result=None, *, loop=None)
- 阻塞 delay 指定的秒数, 如果指定了
result
,则当协程完成时将其返回给调用者,sleep()
总是会挂起当前任务,以允许其他任务运行
- 阻塞 delay 指定的秒数, 如果指定了
并发运行
-
awaitable asyncio.gather(*aws, loop=None, return_exceptions=False)
- 并发运行
aws
序列中的可等待对象 - 如果
aws
中某个可等待对象为协程,将自动作为一个任务加入日程 - 如果所有可等待对象都成功完成,结果将返回一个和
aws
中顺序一致的列表 - 如果
return_exceptions
为False
,在遇到第一个异常时,gather
将被标记为已完成,在此情况下,aws
序列中其他的对象将不可以被取消 - 如果
return_exceptions
为True
, 异常会和成功的结果一起返回 - 如果
aws
中任意一个被取消,则等价于CancelledError
异常,gather
不会被取消
- 并发运行
-
coroutine asyncio.wait(aws, *, loop=None, timeout=None, return_when=ALL_COMPLETED)
- 并发运行
aws
序列中的可等待对象,并阻塞线程直到return_when
- 用法:
done, pending = await asyncio.wait(aws)
,返回两个Future
集合 return_when
的取值包括:FIRST_COMPLETED
,FIRST_EXCEPTION
,ALL_COMPLETED
wait()
会自动将协程作为任务
加入日程,以后将以 (done, pending) 集合形式返回显式创建的任务对象
- 注意对比
wait()
和gather()
方法
- 并发运行
-
asyncio.as_completed(aws, *, loop=None, timeout=None)
- 并发运行
aws
中可等待对象,返回一个协程迭代器。
- 并发运行
注意 wait
async def foo():
return 42
coro = foo()
done, pending = await asyncio.wait({coro})
if coro in done:
# This branch will never be run!
task = asyncio.create_task(foo())
done, pending = await asyncio.wait({task})
if task in done:
# Everything will work as expected now.
三种方式样例
async def phase(i):
print('in phase {}'.format(i))
await asyncio.sleep(0.5 - (0.1 * i))
print('done with phase {}'.format(i))
return 'phase {} result'.format(i)
async def main_as_completed(num_phases):
print('starting main_as_completed')
phases = [
phase(i)
for i in range(num_phases)
]
print('waiting for phases to complete')
results = []
for next_to_complete in asyncio.as_completed(phases):
answer = await next_to_complete
print('received answer {!r}'.format(answer))
results.append(answer)
print('results: {!r}'.format(results))
return results
async def main_wait(num_phases):
print('starting main_wait')
phases = [
phase(i)
for i in range(num_phases)
]
print('waiting for phases to complete')
done, pending = await asyncio.wait(phases)
results = [t.result() for t in done]
print('results: {!r}'.format(results))
return results
async def main_gather(num_phases):
print('starting main_gather')
phases = [
phase(i)
for i in range(num_phases)
]
print('waiting for phases to complete')
results = await asyncio.gather(*phases)
print('results: {!r}'.format(results))
return results
print('### main_as_completed ###')
asyncio.run(main_as_completed(3))
print('### main_wait ###')
asyncio.run(main_wait(3))
print('### main_gather ###')
asyncio.run(main_gather(3))
"""
### main_as_completed ###
starting main_as_completed
waiting for phases to complete
in phase 2
in phase 0
in phase 1
done with phase 2
received answer 'phase 2 result'
done with phase 1
received answer 'phase 1 result'
done with phase 0
received answer 'phase 0 result'
results: ['phase 2 result', 'phase 1 result', 'phase 0 result']
### main_wait ###
starting main_wait
waiting for phases to complete
in phase 2
in phase 1
in phase 0
done with phase 2
done with phase 1
done with phase 0
results: ['phase 1 result', 'phase 0 result', 'phase 2 result']
### main_gather ###
starting main_gather
waiting for phases to complete
in phase 0
in phase 1
in phase 2
done with phase 2
done with phase 1
done with phase 0
results: ['phase 0 result', 'phase 1 result', 'phase 2 result']
"""
- 注意这三种方法的调用方式
gather
是顺序的,可以返回异常信息,等待所有结果as_completed
返回一个迭代器,不保证顺序,不等带返回结果wait
返回一个元组,不保证顺序,等待返回结果
屏蔽取消
awaitable asyncio.shield(aw, *, loop=None)
- 保护一个可等待对象,防止被取消
res = await shield(something())
从something
的角度来看,取消操作并没有发生,但是调用者已被取消,所以await
还是会引发CancelledError
超时
coroutine asyncio.wait_for(aw, timeout, *, loop=None)
- 等待一个
awaitable
对象返回,并且在timeout
秒之后超时
- 等待一个
线程安全
asyncio.run_coroutine_threadsafe(coro, loop)
- 向指定事件循环提交一个协程
内省
asyncio.current_task(loop=None)
- 返回当前运行的
task
实例,如果没有,则返回None
- 返回当前运行的
asyncio.all_tasks(loop=None)
- 返回事件循环所运行的未完成的
task
对象的集合。
- 返回事件循环所运行的未完成的
Task对象
class asyncio.Task(coro, *, loop=None, name=None)
Task
是future
的子类,用来在事件循环
中运行协程。如果一个协程在等待一个Future
对象,Task
对象会挂起该协程的执行并等待该Future
对象完成。- 可使用高层级的
asyncio.create_task()
创建,也可使用低层级的loop.create_task() 或 ensure_future()
来创建 - Task 对象支持
contextvars
模块。当一个 Task 对象被创建,它将复制当前上下文,然后在复制的上下文中运行其协程。
cancel()
- 取消一个正在运行的task,抛出一个
CancelledError
异常,如果取消期间一个协程正在等待一个future
对象,改future
对象也将被取消
- 取消一个正在运行的task,抛出一个
cancelled()
task
是否被取消
done()
task
是否完成
result()
task
的结果
exception()
- 返回一个
task
对象的异常
- 返回一个
源码片段
def create_task(coro):
"""Schedule the execution of a coroutine object in a spawn task.
Return a Task object.
"""
loop = events.get_running_loop()
return loop.create_task(coro)
def create_task(self, coro):
"""Schedule a coroutine object.
Return a task object.
"""
self._check_closed()
if self._task_factory is None:
task = tasks.Task(coro, loop=self)
if task._source_traceback:
del task._source_traceback[-1]
else:
task = self._task_factory(self, coro)
return task