13518219792

建站动态

根据您的个性需求进行定制 先人一步 抢占小程序红利时代

Python协程与JavaScript协程的对比

 前言

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

成都创新互联公司是一家专注于网站制作、网站设计与策划设计,霞浦网站建设哪家好?成都创新互联公司做网站,专注于网站建设十载,网设计领域的专业建站公司;建站业务涵盖:霞浦等地区。霞浦做网站价格咨询:028-86922220

这里大致做下横向对比和总结,便于对这两个语言有兴趣的新人理解和吸收。

共同诉求

什么是协程?

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

混乱的历史

Python 协程的进化

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

 
 
 
  1. def foo(): 
  2.     print("foo start") 
  3.     a = yield 1 
  4.     print("foo a", a) 
  5.     yield 2 
  6.     yield 3 
  7.     print("foo end") 
  8. gen = foo() 
  9. # print(gen.next()) 
  10. # gen.send("a") 
  11. # print(gen.next()) 
  12. # print(foo().next()) 
  13. # print(foo().next()) 
  14. # 在python3.x版本中,python2.x的g.next()函数已经更名为g.__next__(),使用next(g)也能达到相同效果。 
  15. # next()跟send()不同的地方是,next()只能以None作为参数传递,而send()可以传递yield的值. 
  16. print(next(gen)) 
  17. print(gen.send("a")) 
  18. print(next(gen)) 
  19. print(next(foo())) 
  20. print(next(foo())) 
  21. list(foo()) 
  22. """ 
  23. foo start 
  24. foo a a 
  25. foo start 
  26. foo start 
  27. foo start 
  28. foo a None 
  29. foo end 
  30. """

JavaScript 协程的进化

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

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

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

 
 
 
  1. function* foo() { 
  2.     console.log("foo start") 
  3.     a = yield 1; 
  4.     console.log("foo a", a) 
  5.     yield 2; 
  6.     yield 3; 
  7.     console.log("foo end") 
  8. const gen = foo(); 
  9. console.log(gen.next().value); // 1 
  10. // gen.send("a") // http://www.voidcn.com/article/p-syzbwqht-bvv.html SpiderMonkey引擎支持 send 语法 
  11. console.log(gen.next().value); // 2 
  12. console.log(gen.next().value); // 3
  13. console.log(foo().next().value); // 1 
  14. console.log(foo().next().value); // 1 
  15. /* 
  16. foo start 
  17. foo a undefined 
  18. foo start 
  19. foo start 
  20. */

Python 协程成熟体

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

协程(coroutine)

任务(Task 对象):

未来对象(Future):

几种事件循环(event loop):

例子 

 
 
 
  1. import asyncio 
  2. import time 
  3. async def exec(): 
  4.     await asyncio.sleep(2) 
  5.     print('exec') 
  6. # 这种会和同步效果一直 
  7. # async def go(): 
  8. #     print(time.time()) 
  9. #     c1 = exec() 
  10. #     c2 = exec() 
  11. #     print(c1, c2) 
  12. #     await c1 
  13. #     await c2 
  14. #     print(time.time()) 
  15. # 正确用法 
  16. async def go(): 
  17.     print(time.time()) 
  18.     await asyncio.gather(exec(),exec()) # 加入协程组统一调度
  19.     print(time.time()) 
  20. if __name__ == "__main__": 
  21.     asyncio.run(go())

JavaScript 协程成熟体

Promise 继续使用

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

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

async、await语法糖

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

js 异步执行的运行机制

  1.  所有任务都在主线程上执行,形成一个执行栈。
  2.  主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  3.  一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列"。那些对应的异步任务,结束等待状态,进入执行栈并开始执行。

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

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

例子 

 
 
 
  1. var sleep = function (time) { 
  2.     console.log("sleep start") 
  3.     return new Promise(function (resolve, reject) { 
  4.         setTimeout(function () { 
  5.             resolve(); 
  6.         }, time); 
  7.     }); 
  8. }; 
  9. async function exec() { 
  10.     await sleep(2000); 
  11.     console.log("sleep end") 
  12. async function go() { 
  13.     console.log(Date.now()) 
  14.     c1 = exec() 
  15.     console.log("-------1") 
  16.     c2 = exec() 
  17.     console.log(c1, c2) 
  18.     await c1; 
  19.     console.log("-------2") 
  20.     await c2; 
  21.     console.log(c1, c2) 
  22.     console.log(Date.now()) 
  23. }
  24. go();

event loop 将任务划分:

扩展阅读 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 关于事件循环的可比性更高些,这里还需需要继续学习

到这里就基本结束了,看完不知道你会有什么感想,如有错误还请不吝赐教。


分享标题:Python协程与JavaScript协程的对比
文章地址:http://cdbrznjsb.com/article/djjodeo.html

其他资讯

让你的专属顾问为你服务