亲宝软件园·资讯

展开

Python 协程与 JavaScript 协程

佚名 人气:0

1、前言

2、什么是协程?

总结一句话,协程就是满足下面条件的函数:

  •  可以暂停执行(暂停的表达式称为暂停点)
  •  可以从挂起点恢复(保留其原始参数和局部变量)
  •  事件循环是异步编程的底层基石

3、混乱的历史

3.1 Python 协程的进化

在主线发展过程中,也出现了很多支线的协程实现如 Gevent

def foo():  
    print("foo start")  
    a = yield 1  
    print("foo a", a)  
    yield 2  
    yield 3  
    print("foo end")  
gen = foo()  
# print(gen.next())  
# gen.send("a")  
# print(gen.next())  
# print(foo().next())  
# print(foo().next())  
# 在python3.x版本中,python2.x的g.next()函数已经更名为g.__next__(),使用next(g)也能达到相同效果。  
# next()跟send()不同的地方是,next()只能以None作为参数传递,而send()可以传递yield的值.  
print(next(gen))  
print(gen.send("a"))  
print(next(gen))  
print(next(foo()))  
print(next(foo()))  
list(foo())  
"""  
foo start  
1  
foo a a  
2  
3  
foo start  
1  
foo start  
1  
foo start  
foo a None  
foo end  
""" 

4、JavaScript 协程的进化

Promise 中也利用了回调函数。在 then catch 方法中都传入了一个回调函数,分别在 Promise 被满足和被拒绝时执行,这样就就能让它能够被链接起来完成一系列任务。

总之就是把层层嵌套的 callback 变成 .then().then()...,从而使代码编写和阅读更直观。

生成器 Generator 的底层实现机制是协程 Coroutine

function* foo() {  
    console.log("foo start")  
    a = yield 1;  
    console.log("foo a", a)  
    yield 2;  
    yield 3;  
    console.log("foo end")  
}  
const gen = foo();  
console.log(gen.next().value); // 1  
// gen.send("a") // http://www.voidcn.com/article/p-syzbwqht-bvv.html SpiderMonkey引擎支持 send 语法  
console.log(gen.next().value); // 2  
console.log(gen.next().value); // 3 
console.log(foo().next().value); // 1  
console.log(foo().next().value); // 1  
/*  
foo start  
1  
foo a undefined  
2  
3  
foo start  
1  
foo start  
1  
*/ 

5、Python 协程成熟体

可等待对象可以在 await 语句中使用,可等待对象有三种主要类型:协程(coroutine), 任务(task) 和 Future

5.1 协程(coroutine)

5.2 任务(Task 对象)

5.3 未来对象(Future)

 Future 对象用来链接 底层回调式代码 和高层异步/等待式代码。
 不用回调方法编写异步代码后,为了获取异步调用的结果,引入一个 Future 未来对象。Future 封装了与 loop 的交互行为,add_done_callback 方法向 epoll 注册回调函数,当 result 属性得到返回值后,会运行之前注册的回调函数,向上传递给 coroutine

5.4几种事件循环(event loop)

例子:

import asyncio  
import time  
async def exec():  
    await asyncio.sleep(2)  
    print('exec')  
# 这种会和同步效果一直  
# async def go():  
#     print(time.time())  
#     c1 = exec()  
#     c2 = exec()  
#     print(c1, c2)  
#     await c1  
#     await c2  
#     print(time.time())  
# 正确用法  
async def go():  
    print(time.time())  
    await asyncio.gather(exec(),exec()) # 加入协程组统一调度 
    print(time.time())  
if __name__ == "__main__":  
    asyncio.run(go()) 

6、JavaScript 协程成熟体

6.1Promise 继续使用

Promise 本质是一个状态机,用于表示一个异步操作的最终完成 (或失败), 及其结果值。它有三个状态:

最终 Promise 会有两种状态,一种成功,一种失败,当 pending 变化的时候,Promise 对象会根据最终的状态调用不同的处理函数。

6.2 async、await语法糖

asyncawait 是对 Generator Promise 组合的封装,使原先的异步代码在形式上更接近同步代码的写法,并且对错误处理/条件分支/异常堆栈/调试等操作更友好。

6.3 js 异步执行的运行机制

遇到同步任务直接执行,遇到异步任务分类为宏任务(macro-task)和微任务(micro-task)。

当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。

例子:

var sleep = function (time) {  
    console.log("sleep start")  
    return new Promise(function (resolve, reject) {  
        setTimeout(function () {  
            resolve();  
        }, time);  
    });  
};  
async function exec() {  
    await sleep(2000);  
    console.log("sleep end")  
}  
async function go() {  
    console.log(Date.now())  
    c1 = exec()  
    console.log("-------1")  
    c2 = exec()  
    console.log(c1, c2)  
    await c1;  
    console.log("-------2")  
    await c2;  
    console.log(c1, c2)  
    console.log(Date.now())  
} 
go();

6.4 event loop 将任务划分

 主线程循环从"任务队列"中读取事件
 宏队列macro task)js 同步执行的代码块,setTimeoutsetIntervalXMLHttprequestsetImmediate、I/O、UI rendering等,本质是参与了事件循环的任务
微队列(micro task)Promiseprocess.nextTick(node环境)、Object.observeMutationObserver等,本质是直接在 Javascript 引擎中的执行的没有参与事件循环的任务
扩展阅读 Node.js 中的 EventLoop (Javascript 运营机制详解再浅谈 Event Loop)

7、总结与对比

说明 python JavaScript 点评
进程 单进程 单进程 一致
中断/恢复 yield,yield from,next,send yield,next 基本相同,但 JavaScript 对 send 没啥需求
未来对象(回调包装) Futures Promise 解决 callback,思路相同
生成器 generator Generator 将 yield 封装为协程Coroutine,思路一样
成熟后关键词 async、await async、await 关键词支持,一毛一样
事件循环 asyncio 应用的核心。事件循环会运行异步任务和回调,执行网络 IO 操作,以及运行子进程。asyncio 库支持的 API 较多,可控性高 基于浏览器环境基本是黑盒,外部基本无法控制,对任务有做优先级分类,调度方式有区别 这里有很大区别,运行环境不同,对任务的调度先后不同,Python 可能和 Node.js 关于事件循环的可比性更高些,这里还需需要继续学习

到此这篇关于Python 协程与 JavaScript 协程的对比的文章就介绍到这了,更多相关Python 协程与 JavaScript 协程内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

加载全部内容

相关教程
猜你喜欢
用户评论