python的asyncio模组(五):Future对象与Task对象

前言

这篇文章需要对javascript的promise有基本的认识,对不熟的读者可能不太友善,需要自行google,请大家海涵orz

上一篇教学python的asyncio模组(四):Event loop常用API讲了关于Event loop常用的几个method,其中介绍了两个method:

loop.create_task(coro)loop.create_future()

这两个method一个回传task对象,一个回传future对象,上一篇教学我们把他视为类似的东西,但仔细研究后这两种对象在意义与用途上其实差异不小。

事实上这两个对象确实是有相似的结构,Task对象是从Future对象继承过来的,所以Future对象所拥有的method,Task对象也有,但是这两个对象被发明出来的目的是很不一样的。

Future对象的意义

我们大概都了解,创立一个类别的目的,就是将一堆流程与行为或是事物之间的关係抽象化为一个概念,所以一个好的类别,能够完好的描述一个概念,并能描述这个概念之下相关连的一些行为。

那Future对象是用来描述怎样的一个概念呢?

顾名思义,future代表未来,很多其他教学文件说Future对象代表一个还未执行或还未完成的任务的结果,而这的确也指涉了一个未来的概念,这是一个在未来才会出现的结果。

也可以从Javascript的Promise来思考这件事,Promise代表一个未来才会完成的操作,或是一个承诺,看看他有两个method:then还有catch,相当于:

我承诺未来完成某操作后会再继续完成某事 --> then method在做的事情我承诺未来若某操作失败会做怎样的处理 --> catch method在做的事情

而这也代表着一种未来的概念,或也能说他代表一个未完成的任务,因此他和Future对象想要表达的是很类似的东西。

那这个代表未来的或未完成任务的Future对象会有什么method呢?

若从一个未完成任务的角度来看,我们对这个Future对象最关心的就是,到底他完成后会得到什么?会成功还是失败?完成之后我们还会做什么?

所以他的method都围绕这几个问题而设计:

观察现在Future的状态

done() 察看这个任务是否已经完成(成功或失败)cancelled() 察看这个任务是否已经被取消

指定任务的结果

cancel() 取消任务的执行set_result() 判定任务成功,并指定执行完的结果set_exception() 判定任务失败,并指定途中出现的exception

取得任务结果

result() 取得任务成功时的结果,若任务未成功则为Noneexception() 取得任务失败时的exception,若任务未失败则为None

指定任务完成后续要进行的行为

add_done_callback() 指定若任务完成后要执行的callbackremove_done_callback() 取消若任务完成后要执行的callback

而Future在实务上的主要用途是设计异步程式,Event_loop会拿到很多待完成和未完成的任务,并一遍又一遍的进行轮询,而这些任务都要以Future对象的结构加进Event_loop裏面。

Task对象的意义

上面在讲Future的时候发现完全没有提到Coroutine,这是因为Future的method裏面完全没有使用到Coroutine,虽然Future是紧贴着asyncio的Event loop而设计的,但这不表示Future需要Coroutine,甚至asyncio的Event loop也不一定要Coroutine才能完成异步程式喔!

Future充其量只是一个描述概念的框架,也制定了一些能被Event loop所使用的基本方法,而Task对象继承了Future对象的一些基本method,另外其在执行__init__进行初始化的时候,会多传入一个Coroutine参数。

仔细研究原始码会发现Task对象裏面有一个非常重要的method叫作_step,他扮演了Coroutine和Event loop的沟通桥樑,对内负责Coroutine的执行,对外又因为继承了Future的method所以能被Event loop所使用。

简而言之,Task对象有着Future对象的外壳,能被Event loop所使用,对内又能嵌入Coroutine,让Coroutine成为这个未完成任务的实际内容。

至于更详细一点的说明之后会再开一个asyncio源码解析的系列文章,这里就不深究下去了。

Future对象的使用

前面讲了一堆概念性的东西,现在用code示範一下Future对象不需要Coroutine也能够正常运行。

下面我们用Future来简单模拟javascript里的promise物件吧!

let promise_example = (success_or_fail) => {    return new Promise((resolve, reject) => {        console.log("Start exec promise_example, success_or_fail === "+success_or_fail);        setTimeout(()=> {            if (success_or_fail === 'success') {                resolve('success');            } else if (success_or_fail === 'fail'){                reject(new Error('fail'));            }        }, 1000);    });}let success_promise = promise_example('success');let fail_promise = promise_example('fail');success_promise.then((value) => {    console.log('exec success_promise resolve callback');    console.log(value);}).catch((err) => {    console.log('exec success_promise reject callback');    console.log(err.message);});fail_promise.then((value) => {    console.log('exec fail_promise resolve callback');    console.log(value);}).catch((err) => {    console.log('exec fail_promise reject callback');    console.log(err.message);});

上面的Javascript程式创建了一个可以产生两种promise的函数promise_example,其中success_promise会在停住一秒后resolve('success'),另一个fail_promise在停住一秒后reject('fail')。

然后分别对两种promise串上一个then method和catch method,接下来就不详述promise的原理了,恳请不熟悉promise的读者查一下网路的其他教学XD,我们直结揭晓程式执行结果:

Start exec promise_example, success_or_fail === successStart exec promise_example, success_or_fail === failexec success_promise resolve callbacksuccessexec fail_promise reject callbackfail

那如果要用asyncio的Future去实作一模一样的功能,那会像以下的程式:

# python3.5# ubuntu 16.04import asynciodef promise_example(success_or_fail, future):    print("Start exec promise_example, success_or_fail === "+success_or_fail)    future._loop.call_later(1, setTimeout_func, success_or_fail, future)def setTimeout_func(success_or_fail, future):    if success_or_fail == 'success':        future.set_result('success')    elif success_or_fail == 'fail':        future.set_exception(Exception('fail'))def success_callback(future):    try:        if future.result() is not None:            print('exec success_promise resolve callback')            print(future.result())    except Exception as e:        print('exec success_promise reject callback')        print(e)def fail_callback(future):    try:        if future.result() is not None:            print('exec fail_promise resolve callback')            print(future.result())    except Exception as e:        print('exec fail_promise reject callback')        print(e)loop = asyncio.get_event_loop()success_future = loop.create_future()fail_future = loop.create_future()success_future.add_done_callback(success_callback)fail_future.add_done_callback(fail_callback)loop.call_soon(promise_example, 'success', success_future)loop.call_soon(promise_example, 'fail', fail_future)loop.run_until_complete(asyncio.wait([success_future, fail_future]))

如果要详细解说上面提到的python语法,可能会增加过多的篇幅,所以第五篇的系列文就先到这篇吧!剩下的内容会在第六篇继续探讨。

下一篇教学:
python的asyncio模组(六):Future对象与Task对象(二)

参考资料:
python Task对象官方文件说明
https://docs.python.org/3.5/library/asyncio-task.html
Future对象的使用
https://medium.com/@lanf0n/%E5%BE%9E-asyncio-%E9%96%8B%E5%A7%8B-callback-c60a74c54743


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章