先来複习一下前面的教学:
上上一篇的python的asyncio模组(二):异步程式设计基本概念,我们学到异步程式设计的3个基本概念:
事件迴圈(Event loop)事件(Event)回调函数(Callback)上一篇的python的asyncio模组(三):建立Event Loop和定义协程,我们得知如何定义asyncio程式的两个最基本的要素:
事件迴圈(Event loop)协程(Coroutine)其中Coroutine能中途暂停和恢复运作的特性可以很好的实现异步程式设计中的Event与Callback两个概念,又能避免以前残害javascript开发者许久的callback hell。
因为当我们要在一个Coroutine里中途监听某一个Event发生后再执行后续行为时,只需要用await关键字来等待某个Event发生:
def a_coroutine(): # do something... ... await listen_event_happend() # do something after event happend... ...
而不需要明确定义需要监听的Event以及对应的Callback,并注册到Event loop里,这就很可能会导致callback hell的状况:
def a_coroutine(): # do something... ... def do_something_after_event_happend(): # do something after event happend... ... register_to_event_loop(listen_event_happend, do_something_after_event_happend)
若上面的例子还闻不出callback hell的味道,可以请读者想想看以下的例子,要如何改成需要明确定义Event和Callback的写法:
def a_coroutine(): # do something... ... await listen_event1_happend() # do something after event1 happend... ... await listen_event2_happend() # do something after event2 happend... ... await listen_event3_happend() # do something after event3 happend... ...
因为Coroutine和一般的函数特性有一些本质上的差异,他可以中途暂停等待某个事件发生,所以我们对于一个Coroutine的业务操作,会比一般的函数还要更多,所以asyncio所衍生出来的基本语法就看起来非常的多样且複杂。
但若掌握了一些基本的方向,对于常用的基本语法,我们还是能逐步的了解这些语法为何被发明出来且如何被使用。
我们必须先了解,当我们定义了一个Coroutine function后,一直到这个function被Event loop执行的过程中,这个function会经历几次的对象转换:
Coroutine function --> Coroutine object --> Task
我们可以从以下例子了解到其中的对象转换过程:
# python3.5# ubuntu 16.04import asyncioasync def func(): print('func start') await asyncio.sleep(1) print('func end')loop = asyncio.get_event_loop() # 建立一个Event loopprint(func) # 原本是一个coroutine functionobj=func()print(obj) # 执行之后回传一个coroutine objecttask = asyncio.ensure_future(obj)print(task) # 经过ensure_future包装成一个Future对象(也可以说是一个Task对象,两者的差别下一篇教学会说明)loop.run_until_complete(task) # 把task丢入Event loop执行,并在task结束时结束Event loop'''Output:<function func at 0x7f28e365aa70><coroutine object func at 0x7f28e365a9e0><Task pending coro=<func() running at test.py:3>>func startfunc end'''
当我们执行coroutine function之后,并不会真得到执行的结果,事实上function也没有执行,而是得到一个协程对象(coroutine object)。
然后ensure_future会把coroutine object封装程一个task对象,在python的asyncio模组(三):建立Event Loop和定义协程就有提到过,这个对象可以储存任务执行时的状态与环境,所以coroutine才能暂停与恢复运行。
2020/05/24更新
coroutine object本身就能储存任务执行时的状态与环境,而task对象是作为Event loop和coroutine的沟通介面
然后这个Task对象才能真正丢入Event loop下去执行,但就上面的程式来说,我们也可以把coroutine object作为参数丢进loop.run_until_complete,只是在run_until_complete里也还是会把coroutine object转成Task对象再去执行。
接下来我们来讲一下和Event loop有关的一些常用基本语法:
loop.run_until_complete(future)这个函数接收一个Task对象,并指定这个Event loop若执行完这个被传入Task就会停止,不管loop裏面还有没有其他的Task正在执行当中或是等待执行。
而如同上面所说,这个参数也可以传入coroutine object,只是在放入Event loop执行前,这个coroutine object会先被转成Task对象。
loop.run_forever()loop.create_task(coro)顾名思义,这个函数会让一个loop无止境的运行下去,就算当中所有Task已经被执行完毕只剩下空的loop在运转,除非在程式中呼叫loop.stop()才能够停止这个Event loop。
这个函数会接收一个coroutine object,并包装成一个Task对象,同时把这个Task注册到这个Event loop中等待执行。
而当loop.run_until_complete或loop.run_forever被呼叫时,这些被注册进去的Task才会被执行。
loop.create_future()这个函数不接收任何的参数,然后会回传一个空的Future对象,并注册到Event loop裏面等待执行。
目前可以视Future对象和Task对象为一样的东西,两者定义上的差别下一次会说明。
loop.is_running()loop.is_closed()判定一个Event loop是否还在运作。
loop.stop()判定一个Event loop是否已经被close掉。
loop.close()stop一个Event loop。
close掉一个Event loop。
下一篇教学:
python的asyncio模组(五):Future对象与Task对象
参考资料:
https://www.jianshu.com/p/b5e347b3a17c
https://www.dongwm.com/post/understand-asyncio-2/
https://juejin.im/post/5c2f12ce6fb9a04a006f2659