以前没怎么接触前端,对 JavaScript 的异步操作不了解,现在有了点了解。一查发现 Python 和 JavaScript 的协程发展史简直就是一毛一样!

成都创新互联公司是一家专注于网站制作、网站设计与策划设计,霞浦网站建设哪家好?成都创新互联公司做网站,专注于网站建设十载,网设计领域的专业建站公司;建站业务涵盖:霞浦等地区。霞浦做网站价格咨询:028-86922220
这里大致做下横向对比和总结,便于对这两个语言有兴趣的新人理解和吸收。
总结一句话,协程就是满足下面条件的函数:
在主线发展过程中,也出现了很多支线的协程实现如 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
 - """
 
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
 - */
 
可等待对象可以在 await 语句中使用,可等待对象有三种主要类型:协程(coroutine), 任务(task) 和 Future。
- 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())
 
Promise 本质是一个状态机,用于表示一个异步操作的最终完成 (或失败), 及其结果值。它有三个状态:
最终 Promise 会有两种状态,一种成功,一种失败,当 pending 变化的时候,Promise 对象会根据最终的状态调用不同的处理函数。
async、await 是对 Generator 和 Promise 组合的封装,使原先的异步代码在形式上更接近同步代码的写法,并且对错误处理/条件分支/异常堆栈/调试等操作更友好。
遇到同步任务直接执行,遇到异步任务分类为宏任务(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();
 
扩展阅读 Node.js 中的 EventLoop (http://www.ruanyifeng.com/blog/2014/10/event-loop.html)
| 说明 | 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 关于事件循环的可比性更高些,这里还需需要继续学习 | 
到这里就基本结束了,看完不知道你会有什么感想,如有错误还请不吝赐教。
Copyright © 2009-2022 www.wtcwzsj.com 青羊区广皓图文设计工作室(个体工商户) 版权所有 蜀ICP备19037934号