当前位置: 首页 > 后端技术 > Python

Python协程与JavaScript协程对比

时间:2023-03-26 01:05:01 Python

前言之前接触前端的不多,对JavaScript的异步操作了解不多。现在我有点明白了。搜索了一下,发现Python和JavaScript的协程的发展历史几乎是一样的!这里做一个大致的横向比较和总结,方便对这两种语言感兴趣的新手理解和吸收。共同诉求多核CPU,由于自身历史原因(单线程环境)需要实现并发功能,简化代码,避免回调地狱,关键字支持有效利用操作系统资源和硬件:与线程相比,协程占用资源更少,上下文更快什么是协程?综上所述,协程是满足以下条件的函数:可以暂停执行(暂停的表达式称为暂停点),可以从暂停点恢复(保留其原始参数和局部变量)事件循环是异步编程的底层基石混沌历史Python协程的演化Python2.2首次引入了生成器Python2.5在Python3.4的语法中加入了yield关键字yieldfrom(yieldfrom约等于yield+异常处理+send),实验引入的异步I/O框架asyncio(PEP3156)在Python3中添加了async/await语法(PEP492)。)在主线的发展过程中,也出现了Gevent等很多支线实现。deffoo():print("foostart")a=yield1print("fooa",a)yield2yield3print("fooend")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的值。打印(下一个(gen))打印(gen.send(“a”))打印(下一个(gen))打印(下一个(foo()))打印(下一个(foo()))列表(foo())“""foostart1fooaa23foostart1foostart1foostartfooaNonefooend"""JavaScript协程进化同步代码异步JavaScript:回调hellES6引入Promise/a+,generatorGenerators(语法functionfoo(){}*可以赋予函数挂起/保存上下文/恢复执行状态),新关键字yield使生成设备功能被暂停。ES7引入了asyncfunction/await语法糖,async可以声明一个异步函数(将Generator函数和自动执行器包装在一个函数中),这个函数需要返回一个Promise对象。await可以等待Promise对象解析,并获得结果。Promise也使用了回调函数。then和catch方法都传入一个回调函数,分别在Promise完成和拒绝时执行,这样就可以链式完成一系列的任务。简而言之,就是把嵌套的回调变成.then().then()...,让代码的编写和阅读更加直观。Generator的底层实现机制是Coroutine。function*foo(){console.log("foostart")a=yield1;console.log("fooa",a)yield2;产量3;console.log("fooend")}constgen=foo();console.log(gen.next().value);//1//gen.send("a")//http://www.voidcn.com/article/p-syzbwqht-bvv.htmlSpiderMonkey引擎支持发送语法console.log(gen.next().value);//2console.log(gen.next().value);//3console.log(foo().next().value);//1console.log(foo().next().value);//1/*foostart1fooaundefined23foostart1foostart1*/python协程成熟的waitable对象可以用在await语句中,有三种awaitable对象,主要有协程、任务和Futures三种类型。协程(coroutine)协程函数:以asyncdef形式定义的函数;协程对象:调用协程函数返回的对象老式的基于生成器(generator)的协程任务(Taskobject):任务用于“并行”调度协程,当一个协程通过函数封装为一个任务时,如asyncio.create_task(),协程会被自动调度执行,Task对象用于在事件循环中运行协程。如果协程正在等待Future对象,Task对象将暂停协程的执行并等待Future对象完成。当Future对象完成时,包装的协程将恢复执行。事件循环使用协作调度:事件循环一次运行一个任务对象。任务对象等待Future对象完成,而事件循环运行其他任务、回调或执行IO操作。asyncio.Task继承了Future的所有API,除了Future.set_result()和Future.set_exception()。未来对象(Future):Future对象用于链接低级回调代码和高级异步/等待代码。写完没有回调方法的异步代码后,为了获取异步调用的结果,引入一个Future未来对象。Future封装了与循环的交互。add_done_callback方法向epoll注册一个回调函数。当result属性得到返回值时,会运行之前注册的回调函数,向上传递给协程。几种事件循环:libevent/libev:Gevent使用的网络库(greenlet+早期的libevent,晚期的libev),应用广泛;tornado:由tornado框架本身实现的IOLOP;picoev:meinheld使用的(greenlet+picoev)网络库,体积小,轻量级。与libevent相比,改进了数据结构和事件检测模型,因此速度更快。但是从github上看好像年久失修了,用的人不多。uvloop:Python3时代的新人。Guido创建了asyncio库。Asyncio可以配置一个可插拔的事件循环,但是需要满足相关的API要求。uvloop继承自libuv,并用Python对象包装了一些低级结构和函数。目前的Sanic框架都是基于这个库exampleimportasyncioimporttimeasyncdefexec():awaitasyncio.sleep(2)print('exec')#这种会和同步效果已经#asyncdefgo():#print(time.time())#c1=exec()#c2=exec()#print(c1,c2)#awaitc1#awaitc2#print(time.time())#asyncdefgo()的正确用法:print(time.time())awaitasyncio.gather(exec(),exec())#加入协程组统一调度print(time.time())if__name__=="__main__":asyncio.run(go())JavaScriptcoroutine成熟体Promise继续使用Promise本质是一个状态机,用来表示一个异步操作的最终完成(或失败)及其结果值。它有三种状态:pending:初始状态,既不成功也不失败的状态。fulfilled:表示操作成功完成。rejected:表示操作失败。Promise最终会有两种状态,一种是成功,一种是失败。当pending变化时,Promise对象会根据最终状态调用不同的处理函数。async,await语法糖async,await是Generator和Promise结合的封装,使得原来的异步代码在形式上更接近于同步代码,对错误处理/条件分支/异常堆栈/调试等操作更加友好.js异步执行的运行机制所有的任务都在主线程上执行,形成一个执行栈。除了主线程之外,还有一个“任务队列”。只要异步任务有运行结果,就会在“任务队列”中放入一个事件。一旦“ExecutionStack”中的所有同步任务都执行完毕,系统就会读取“TaskQueue”。那些对应的异步任务结束等待状态,进入执行栈并开始执行。同步任务直接执行,异步任务分为宏任务和微任务。当当前执行栈执行完毕后,立即处理microtask队列中的所有事件,然后从macrotask队列中取出一个事件。在同一个事件循环中,微任务总是在宏任务之前执行。示例varsleep=function(time){console.log("sleepstart")returnnewPromise(function(resolve,reject){setTimeout(function(){resolve();},async);};functionexec(){awaitsleep(2000);console.log("sleepend")}asyncfunctiongo(){console.log(Date.now())c1=exec()console.log("-------1")c2=exec()console.log(c1,c2)awaitc1;console.log("-------2")awaitc2;console.log(c1,c2)console.log(Date.now())}go();eventloop分任务:主线程循环从“任务队列”中读取事件宏队列(宏任务)js同步执行的代码块,setTimeout,setInterval,XMLHttprequest,setImmediate、I/O、UI渲染等,本质是参与事件循环任务微队列(microtask)Promise、process.nextTick(节点环境)、Object.observe、MutationObserver等,本质是直接在Javascript引擎中执行的任务,不参与事件循环延伸阅读EventLoop总结与比较inNode.jsRequirefutureobjects(回调封装)FuturesPromise解决方案callback,思路是一样的,生成器generatorGenerator将yield封装为协程Coroutine,思路成熟后,支持关键字async,awaitasync,await,事件循环也是一样的。asyncio应用程序的核心事件循环将运行异步任务和回调,执行网络IO操作,并运行子进程。asyncio库支持很多API,可控性强。基于浏览器环境,它基本上是一个黑盒子,外面基本上是不可控的。任务有优先级,调度方式不同。这里有很大的不同。运行环境不同。时间表不同。Python在事件循环方面可能比Node.js更具可比性。你还需要在这里继续学习。到这里基本就结束了。不知道你看完之后有什么感想。请随时犯任何错误。开导我。以上就是本次分享的全部内容。觉得文章还不错的话,请关注公众号:Python编程学习圈,每日干货分享,发送“J”还能领取大量学习资料。或者去编程学习网了解更多编程技术知识。