Python3中的Futures与ES6中的Promise之间的差异

Der*_*會功夫 19 javascript python future promise python-asyncio

从Python 3.5开始,关键字awaitasync语言都被引入.现在,我更像是一个Python 2.7人,而且我已经在相当长一段时间内避免使用Python 3了,所以asyncio对我来说这是一个新手.根据我的理解,它似乎await/async与它们在ES6(或JavaScript,ES2015中的工作方式)的工作方式非常相似,但是您想要称之为.

这是我用来比较它们的两个脚本.

import asyncio

async def countdown(n):
    while n > 0:
        print(n)
        n -= 1
        await asyncio.sleep(1)

async def main():
    """Main, executed in an event loop"""

    # Creates two countdowns
    futures = asyncio.gather(
        countdown(3), 
        countdown(2)
    )
    # Wait for all of them to finish
    await futures
    # Exit the app
    loop.stop()

loop = asyncio.get_event_loop()
asyncio.ensure_future(main())
loop.run_forever()
Run Code Online (Sandbox Code Playgroud)
function sleep(n){
    // ES6 does not provide native sleep method with promise support
    return new Promise(res => setTimeout(res, n * 1000));
}

async function countdown(n){
    while(n > 0){
        console.log(n);
        n -= 1;
        await sleep(1);
    }
}

async function main(){
    // Creates two promises
    var promises = Promise.all([
        countdown(3),
        countdown(2)
    ]);
    // Wait for all of them to finish
    await promises;
    // Cannot stop interpreter's event loop
}

main();
Run Code Online (Sandbox Code Playgroud)

有一点需要注意的是,代码非常相似,它们的工作方式基本相同.

以下是问题:

  1. 在Python和ES6中,await/async都基于生成器.认为期货和Promises一样是正确的吗?

  2. 我已经看过这些术语Task,FutureCoroutineasyncio文档中使用.它们之间有什么区别?

  3. 我应该开始编写始终运行事件循环的Python代码吗?

And*_*sky 28

  1. 在Python和ES6中,await/async都基于生成器.认为期货和Promises一样是正确的吗?

不是Future,但是Python Task大致相当于Javascript Promise.请在下面查看更多详情

  1. 我已经看过这些术语Task,FutureCoroutineasyncio文档中使用.它们之间有什么区别?

它们是完全不同的概念.主要TaskFuture和组成Coroutine.让我们简要描述这些原语(我将简化许多事情来描述主要原则):

未来

未来只是一种价值的抽象,可能尚未计算并最终可用.它是一个简单的容器,只做一件事 - 只要设置了值,就会触发所有已注册的回调.

如果要获取该值,请通过add_done_callback()方法注册回调.

但与之不同的是Promise,实际计算是在外部完成的 - 外部代码必须调用set_result()方法来解决未来问题.

协同程序

Coroutine是非常相似的对象Generator.

通常在for循环内迭代生成器.它产生值,并且从PEP342接受开始,它接收值.

协程通常在asyncio库的深度内的事件循环内迭代.一个协程产生Future实例.当您在协程上进行迭代并产生未来时,您应该等到这个未来得到解决.在那之后,你将send未来的价值带入协程,然后你将获得另一个未来,依此类推.

一个await表达式是几乎相同yield from的表达,因此通过等待其他协程,你停止,直到协程有其所有期货交易解决,并获得协同程序的返回值.这Future是一个可迭代的迭代,它的迭代器返回实际的Future - 大致意味着await future等于yield from future等于yield future.

任务

任务是未来,它实际上已经开始计算并附加到事件循环.所以它是一种特殊的Future(类Task派生自类Future),它与一些事件循环相关联,并且它有一些协程,它作为任务执行器.

任务通常由事件循环对象创建:您为循环提供协程,它创建Task对象并开始以上述方式迭代该协程.协程完成后,任务的未来由协程的返回值解决.

你看,这个任务与JS Promise非常相似 - 它封装了后台作业及其结果.

协同功能和异步功能

Coroutine func是coroutines的工厂,就像发电机的发电机功能一样.注意Python的协程函数和Javascript的异步函数之间的区别 - JS async函数在被调用时会创建一个Promise,它的内部生成器会立即开始迭代,而Python的协同程序什么都不做,直到在它上面创建了Task.

  1. 我应该开始编写始终运行事件循环的Python代码吗?

如果您需要任何asyncio功能,那么您应该.事实证明混合同步和异步代码非常困难 - 整个程序最好是异步的(但你可以通过asyncio threadpool API在不同的线程中启动同步代码块)