loop
asyncio.get_event_loop():获得当前context的loop
asyncio.new_event_loop():创建一个新的loop对象
asyncio.set_event_loop(loop):为当前context设置loop
关于context,推测为当前线程的上下文环境。如果asyncio的loop和android中的handler相似,那每条线程都可以有一个loop。不过一般也都只用get_event_loop()就行了
loop的常用API
run_until_complete(future):运行future,并阻塞当前线程直到future运行完毕
run_forever():运行future,并阻塞当前线程,直到该loop的stop()方法被调用
由于run_forever()会一直阻塞当前线程,故只能在future中调用loop的stop()方法
run_forever()stop前未完成的future将在下次执行run_forever()后继续执行。具体的策略我还没搞清楚
stop():停止loop
is_running()
close():关闭loop,所有Pending状态的future和callback函数都将被丢失,且之后不能再运行这个loop
is_close()
call_soon(callback,*args):安排一个函数被尽快执行
call_soon_threadsafe(callback, *args):同上,但是线程安全
call_later(delay, callback, *args):delay的单位是秒
call_at(when, callback, *args):when是一个时间戳
call_soon依旧需要调用loop的run_until_complete或者run_forever才会去执行callback函数,callback就是一个普通函数
call_soon不能把关键字参数传递给callback,如果希望这么做,可以结合functools.partial
loop.call_soon(functools.partial(print, "Hello", flush=True))
大多数asyncio的对象都不是线程安全的,如果需要访问event loop中的对象,就需要使用call_soon_threadsafe方法。比如希望取消一个future,不能直接使用future.cancel,而需要loop.call_soon_threadsafe(future.cancel)
loop的call相关的方法都会返回一个Handle对象,该对象的cancel方法可以用来取消callback函数的执行。如果callback已经被执行或取消,则cancel不起作用
run_coroutine_threadsafe(coro_func,loop):loop必须在主线程中运行,如果希望其他线程去执行协程,需要调用该方法,该方法返回一个Future对象
run_in_executor(executor, func, *args):用ThreadPoolExecutor来执行函数,executor为None,则使用默认的executor
set_default_executor(executor)
如果希望在coroutine中执行异步IO,可以使用run_in_executor方法
Future和Task
几乎兼容concurrent.futures.Future,它包含的方法也几乎等同于concurrent.futures.Future
future有四种状态:Pending、Running、Done、Cancelled
coroutine是协程
future是协程运行的结果
Task是Future的子类,是loop真正执行的任务
应该可以这么理解coroutine被包装成一个task给loop调度执行,而coroutine的await/yield from返回一个future作为其异步操作的执行结果
future可以用add_done_callback设置回调函数,该回调函数会被传入一个参数,参数的值就是当前的future对象
asyncio模块的其他函数
ensure_future(coro_or_future, *, loop=None):安排coroutine对象的执行,返回一个task,该task将在下次loop.run_until_complete或loop.run_forever后被执行;如果loop已经在执行了,那该coroutine会被安排到本次loop的执行中,而不是下一次;如果参数不是coroutine,而是future,则直接返回
gather(*coros_or_futures, loop=None, return_exceptions=False):聚合多个coroutine或者future,返回一个future,直到所有任务都完成后,该future才返回
wait(futures, *, loop=None, timeout=None, return_when=ALL_COMPLETED):类似于gather,聚合future,当然它有其他两种返回时机(FIRST_COMPLETED/FIRST_EXCEPTION)
wait和gather的第一个参数是有很大不同的!
wait接收的是一个future的序列,而gather接收的是任意数量的coroutine或gather对象,也就是说如果有一个coro_seq希望传递给gather,则需要使用*coro_seq
wait返回的是一个generator;而gather返回的是一个future,可以设置callback函数哦
as_completed(fs, *, loop=None, timeout=None):和concurrent.future.as_completed有很大不同。
对于concurrent.future,是执行完一个future,就返回该future,然后即可通过future的result方法来回去结果
对于asyncio,as_completed返回的是一个元素为coroutine的iterator,因为它接收的参数也可以是一个元素为coroutine/future的iterator,感觉像是它对传入的coroutine做了包装?
使用result = await coroutine可以获得原coroutine的返回结果
async def coro_func():
for f in as_completed(fs):
result = await f
从现象上来看,上述代码的for循环中第一次await的时候就会执行完fs中所有的future,后续的await就是直接从future中拿结果,几乎不耗时
可以理解为:as_completed并发执行完所有fs中的coroutine,同时也保持了coroutine的执行顺序
虽然所有coroutine也是并发执行的,但是当前线程却要等到所有coroutine都执行完毕后才能继续,感觉没concurrent.future的as_completed快
多说一句,很容易想当如果直接用for循环迭代fs,而不加as_completed函数的话,就不能达到多个coroutine并发的效果了
asyncio模块提供API来创建子进程以执行shell命令,就像subprocess模块!
asyncio模块提供同步相关的API,lock、event、condition、semaphore等
asyncio也提供普通队列,LIFO队列,优先级队列等API
协程提供了一些与线程的API相对应的API,我觉得协程可以理解为一种线程,这种线程可以指定何时让出CPU