0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Python協(xié)程與JavaScript協(xié)程的對(duì)比及經(jīng)驗(yàn)技巧

馬哥Linux運(yùn)維 ? 來源:從零開始的程序員生活 ? 作者:從零開始的程序員 ? 2021-10-20 14:30 ? 次閱讀

前言以前沒怎么接觸前端,對(duì) JavaScript 的異步操作不了解,現(xiàn)在有了點(diǎn)了解。一查發(fā)現(xiàn) Python 和 JavaScript 的協(xié)程發(fā)展史簡(jiǎn)直就是一毛一樣!這里大致做下橫向?qū)Ρ群涂偨Y(jié),便于對(duì)這兩個(gè)語言有興趣的新人理解和吸收。

共同訴求隨著 cpu 多核化,都需要實(shí)現(xiàn)由于自身歷史原因(單線程環(huán)境)下的并發(fā)功能

簡(jiǎn)化代碼,避免回調(diào)地獄,關(guān)鍵字支持

有效利用操作系統(tǒng)資源和硬件:協(xié)程相比線程,占用資源更少,上下文更快

什么是協(xié)程?總結(jié)一句話,協(xié)程就是滿足下面條件的函數(shù):

可以暫停執(zhí)行(暫停的表達(dá)式稱為暫停點(diǎn))

可以從掛起點(diǎn)恢復(fù)(保留其原始參數(shù)和局部變量)

事件循環(huán)是異步編程的底層基石

混亂的歷史Python 協(xié)程的進(jìn)化

Python2.2 中,第一次引入了生成器

Python2.5 中,yield 關(guān)鍵字被加入到語法中

Python3.4 時(shí)有了 yield from(yield from 約等于 yield + 異常處理 + send), 并試驗(yàn)性引入的異步 I/O 框架 asyncio(PEP 3156)

Python3.5 中新增了 async/await 語法(PEP 492)

Python3.6 中 asyncio 庫(kù)“轉(zhuǎn)正” (之后的官方文檔就清晰了很多)

在主線發(fā)展過程中,也出現(xiàn)了很多支線的協(xié)程實(shí)現(xiàn)如 Gevent。

deffoo():
print("foostart")
a=yield1
print("fooa",a)
yield2
yield3
print("fooend")


gen=foo()
#print(gen.next())
#gen.send("a")
#print(gen.next())
#print(foo().next())
#print(foo().next())

#在python3.x版本中,python2.x的g.next()函數(shù)已經(jīng)更名為g.__next__(),使用next(g)也能達(dá)到相同效果。
#next()跟send()不同的地方是,next()只能以None作為參數(shù)傳遞,而send()可以傳遞yield的值.

print(next(gen))
print(gen.send("a"))
print(next(gen))
print(next(foo()))
print(next(foo()))

list(foo())

"""
foostart
1
fooaa
2
3
foostart
1
foostart
1
foostart
fooaNone
fooend
"""

JavaScript 協(xié)程的進(jìn)化

  • 同步代碼

  • 異步 JavaScript: callback hell

  • ES6 引入 Promise/a+, 生成器 Generators(語法function foo(){}* 可以賦予函數(shù)執(zhí)行暫停/保存上下文/恢復(fù)執(zhí)行狀態(tài)的功能), 新關(guān)鍵詞 yield 使生成器函數(shù)暫停。

  • ES7 引入 async函數(shù)/await語法糖,async 可以聲明一個(gè)異步函數(shù)(將 Generator 函數(shù)和自動(dòng)執(zhí)行器,包裝在一個(gè)函數(shù)里),此函數(shù)需要返回一個(gè) Promise 對(duì)象。await 可以等待一個(gè) Promise 對(duì)象 resolve,并拿到結(jié)果

Promise 中也利用了回調(diào)函數(shù)。在 then 和 catch 方法中都傳入了一個(gè)回調(diào)函數(shù),分別在 Promise 被滿足和被拒絕時(shí)執(zhí)行,這樣就就能讓它能夠被鏈接起來完成一系列任務(wù)。總之就是把層層嵌套的 callback 變成 .then().then()...,從而使代碼編寫和閱讀更直觀。生成器 Generator 的底層實(shí)現(xiàn)機(jī)制是協(xié)程 Coroutine。
function*foo(){
console.log("foostart")
a=yield1;
console.log("fooa",a)
yield2;
yield3;
console.log("fooend")
}

constgen=foo();
console.log(gen.next().value);//1
//gen.send("a")//http://www.voidcn.com/article/p-syzbwqht-bvv.htmlSpiderMonkey引擎支持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

/*
foostart
1
fooaundefined
2
3
foostart
1
foostart
1
*/

Python 協(xié)程成熟體

可等待對(duì)象可以在 await 語句中使用,可等待對(duì)象有三種主要類型:協(xié)程(coroutine), 任務(wù)(task) 和 Future。

協(xié)程(coroutine)

  • 協(xié)程函數(shù):定義形式為 async def 的函數(shù);

  • 協(xié)程對(duì)象:調(diào)用 協(xié)程函數(shù) 所返回的對(duì)象

  • 舊式基于 generator(生成器)的協(xié)程

任務(wù)(Task 對(duì)象):

  • 任務(wù) 被用來“并行的”調(diào)度協(xié)程, 當(dāng)一個(gè)協(xié)程通過 asyncio.create_task() 等函數(shù)被封裝為一個(gè) 任務(wù),該協(xié)程會(huì)被自動(dòng)調(diào)度執(zhí)行

  • Task 對(duì)象被用來在事件循環(huán)中運(yùn)行協(xié)程。如果一個(gè)協(xié)程在等待一個(gè) Future 對(duì)象,Task 對(duì)象會(huì)掛起該協(xié)程的執(zhí)行并等待該 Future 對(duì)象完成。當(dāng)該 Future 對(duì)象 完成,被打包的協(xié)程將恢復(fù)執(zhí)行。

  • 事件循環(huán)使用協(xié)同日程調(diào)度: 一個(gè)事件循環(huán)每次運(yùn)行一個(gè) Task 對(duì)象。而一個(gè) Task 對(duì)象會(huì)等待一個(gè) Future 對(duì)象完成,該事件循環(huán)會(huì)運(yùn)行其他 Task、回調(diào)或執(zhí)行 IO 操作。

  • asyncio.Task 從 Future 繼承了其除 Future.set_result() 和 Future.set_exception() 以外的所有 API。

未來對(duì)象(Future):

  • Future 對(duì)象用來鏈接 底層回調(diào)式代碼 和高層異步/等待式代碼。

  • 不用回調(diào)方法編寫異步代碼后,為了獲取異步調(diào)用的結(jié)果,引入一個(gè) Future 未來對(duì)象。Future 封裝了與 loop 的交互行為,add_done_callback 方法向 epoll 注冊(cè)回調(diào)函數(shù),當(dāng) result 屬性得到返回值后,會(huì)運(yùn)行之前注冊(cè)的回調(diào)函數(shù),向上傳遞給 coroutine。

幾種事件循環(huán)(event loop):

  • libevent/libev:Gevent(greenlet + 前期 libevent,后期 libev)使用的網(wǎng)絡(luò)庫(kù),廣泛應(yīng)用;

  • tornado:tornado 框架自己實(shí)現(xiàn)的 IOLOOP;

  • picoev:meinheld(greenlet+picoev)使用的網(wǎng)絡(luò)庫(kù),小巧輕量,相較于 libevent 在數(shù)據(jù)結(jié)構(gòu)和事件檢測(cè)模型上做了改進(jìn),所以速度更快。但從 github 看起來已經(jīng)年久失修,用的人不多。

  • uvloop:Python3 時(shí)代的新起之秀。Guido 操刀打造了 asyncio 庫(kù),asyncio 可以配置可插拔的event loop,但需要滿足相關(guān)的 API 要求,uvloop 繼承自 libuv,將一些低層的結(jié)構(gòu)體和函數(shù)用 Python 對(duì)象包裝。目前 Sanic 框架基于這個(gè)庫(kù)

例子

importasyncio
importtime


asyncdefexec():
awaitasyncio.sleep(2)
print('exec')

#這種會(huì)和同步效果一直
#asyncdefgo():
#print(time.time())
#c1=exec()
#c2=exec()
#print(c1,c2)
#awaitc1
#awaitc2
#print(time.time())

#正確用法
asyncdefgo():
print(time.time())
awaitasyncio.gather(exec(),exec())#加入?yún)f(xié)程組統(tǒng)一調(diào)度
print(time.time())

if__name__=="__main__":
asyncio.run(go())

JavaScript 協(xié)程成熟體

Promise 繼續(xù)使用

Promise 本質(zhì)是一個(gè)狀態(tài)機(jī),用于表示一個(gè)異步操作的最終完成 (或失敗), 及其結(jié)果值。它有三個(gè)狀態(tài):
  • pending: 初始狀態(tài),既不是成功,也不是失敗狀態(tài)。
  • fulfilled: 意味著操作成功完成。
  • rejected: 意味著操作失敗。
最終 Promise 會(huì)有兩種狀態(tài),一種成功,一種失敗,當(dāng) pending 變化的時(shí)候,Promise 對(duì)象會(huì)根據(jù)最終的狀態(tài)調(diào)用不同的處理函數(shù)。

async、await語法糖

async、await 是對(duì) Generator 和 Promise 組合的封裝,使原先的異步代碼在形式上更接近同步代碼的寫法,并且對(duì)錯(cuò)誤處理/條件分支/異常堆棧/調(diào)試等操作更友好。

js 異步執(zhí)行的運(yùn)行機(jī)制

  1. 所有任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧。

  2. 主線程之外,還存在一個(gè)"任務(wù)隊(duì)列"(task queue)。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件。

  3. 一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會(huì)讀取"任務(wù)隊(duì)列"。那些對(duì)應(yīng)的異步任務(wù),結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧并開始執(zhí)行。

遇到同步任務(wù)直接執(zhí)行,遇到異步任務(wù)分類為宏任務(wù)(macro-task)和微任務(wù)(micro-task)。當(dāng)前執(zhí)行棧執(zhí)行完畢時(shí)會(huì)立刻先處理所有微任務(wù)隊(duì)列中的事件,然后再去宏任務(wù)隊(duì)列中取出一個(gè)事件。同一次事件循環(huán)中,微任務(wù)永遠(yuǎn)在宏任務(wù)之前執(zhí)行。

例子

varsleep=function(time){
console.log("sleepstart")
returnnewPromise(function(resolve,reject){
setTimeout(function(){
resolve();
},time);
});
};

asyncfunctionexec(){
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();

event loop 將任務(wù)劃分:

  • 主線程循環(huán)從"任務(wù)隊(duì)列"中讀取事件

  • 宏隊(duì)列(macro task)js 同步執(zhí)行的代碼塊,setTimeout、setInterval、XMLHttprequest、setImmediate、I/O、UI rendering等,本質(zhì)是參與了事件循環(huán)的任務(wù)

  • 微隊(duì)列(micro task)Promise、process.nextTick(node環(huán)境)、Object.observe, MutationObserver等,本質(zhì)是直接在 Javascript 引擎中的執(zhí)行的沒有參與事件循環(huán)的任務(wù)

總結(jié)與對(duì)比

說明 python JavaScript 點(diǎn)評(píng)
進(jìn)程 單進(jìn)程 單進(jìn)程 一致
中斷/恢復(fù) yield,yield from,next,send yield,next 基本相同,但 JavaScript 對(duì) send 沒啥需求
未來對(duì)象(回調(diào)包裝) Futures Promise 解決 callback,思路相同
生成器 generator Generator 將 yield 封裝為協(xié)程Coroutine,思路一樣
成熟后關(guān)鍵詞 async、await async、await 關(guān)鍵詞支持,一毛一樣
事件循環(huán) asyncio 應(yīng)用的核心。事件循環(huán)會(huì)運(yùn)行異步任務(wù)和回調(diào),執(zhí)行網(wǎng)絡(luò) IO 操作,以及運(yùn)行子進(jìn)程。asyncio 庫(kù)支持的 API 較多,可控性高 基于瀏覽器環(huán)境基本是黑盒,外部基本無法控制,對(duì)任務(wù)有做優(yōu)先級(jí)分類,調(diào)度方式有區(qū)別 這里有很大區(qū)別,運(yùn)行環(huán)境不同,對(duì)任務(wù)的調(diào)度先后不同,Python 可能和 Node.js 關(guān)于事件循環(huán)的可比性更高些,這里還需需要繼續(xù)學(xué)習(xí)

到這里就基本結(jié)束了,看完不知道你會(huì)有什么感想,如有錯(cuò)誤還請(qǐng)不吝賜教。

原文鏈接:https://www.cnblogs.com/lgjbky/p/14759463.html

編輯:jq
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10702

    瀏覽量

    209364
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2943

    瀏覽量

    104099
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4237

    瀏覽量

    61967
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4671

    瀏覽量

    67766
  • 生成器
    +關(guān)注

    關(guān)注

    7

    文章

    313

    瀏覽量

    20844

原文標(biāo)題:Python 協(xié)程與 JavaScript 協(xié)程的對(duì)比

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    晶泰科技與協(xié)鑫集團(tuán)簽署戰(zhàn)略合作協(xié)議

    近日,在蘇州協(xié)鑫能源中心,晶泰科技與協(xié)鑫集團(tuán)共同見證了雙方戰(zhàn)略合作新篇章的開啟,正式簽署了為期五年的戰(zhàn)略合作協(xié)議。此次合作,不僅標(biāo)志著兩大行業(yè)巨頭的強(qiáng)強(qiáng)聯(lián)合,更預(yù)示著新能源材料研發(fā)領(lǐng)域?qū)⒂瓉硪粓?chǎng)由人工智能與自動(dòng)化技術(shù)引領(lǐng)的深刻變革。
    的頭像 發(fā)表于 09-03 14:34 ?312次閱讀

    聲學(xué)測(cè)試掃頻信號(hào)倍頻頻點(diǎn)計(jì)算(SoundCheck)

    聲學(xué)測(cè)試中,經(jīng)常需要用到激勵(lì)信號(hào),不管是測(cè)試揚(yáng)聲器還是麥克風(fēng),通常是輸出一個(gè)標(biāo)準(zhǔn)信號(hào)源,然后采集信號(hào)與標(biāo)準(zhǔn)信號(hào)進(jìn)行對(duì)比,以測(cè)試待測(cè)產(chǎn)品性能,標(biāo)準(zhǔn)音頻可以有多種,參考Soundcheck 軟件,如
    發(fā)表于 08-01 10:58

    鴻蒙輕內(nèi)核源碼分析:MMU 協(xié)處理器

    1、 ARM C15 協(xié)處理器 在 ARM 嵌入式應(yīng)用系統(tǒng)中, 很多系統(tǒng)控制由 ARM CP15 協(xié)處理器來完成的。CP15 協(xié)處理器包含編號(hào) 0-15 的 16 個(gè) 32 位的寄存器。例如,ARM
    的頭像 發(fā)表于 02-20 14:28 ?404次閱讀
    鴻蒙輕內(nèi)核源碼分析:MMU <b class='flag-5'>協(xié)</b>處理器

    談?wù)?b class='flag-5'>協(xié)的那些事兒

    隨著異步編程的發(fā)展以及各種并發(fā)框架的普及,協(xié)作為一種異步編程規(guī)范在各類語言中地位逐步提高。我們不單單會(huì)在自己的程序中使用協(xié),各類框架如fastapi,aiohttp等也都是基于異步
    的頭像 發(fā)表于 01-26 11:36 ?1018次閱讀
    談?wù)?b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>的那些事兒

    BlueNRG系列協(xié)處理器實(shí)戰(zhàn)經(jīng)驗(yàn)簡(jiǎn)介

    BlueNRG 系列芯片從最早的一代 BlueNRG-MS 開始就支持協(xié)處理器模式。
    的頭像 發(fā)表于 01-05 18:16 ?1531次閱讀
    BlueNRG系列<b class='flag-5'>協(xié)</b>處理器實(shí)戰(zhàn)<b class='flag-5'>經(jīng)驗(yàn)</b>簡(jiǎn)介

    何選擇一個(gè)合適的協(xié)來獲得CPU執(zhí)行權(quán)

    協(xié)。更不用說很多活躍的語言如python,java等,也都是支持協(xié)的。盡管這些協(xié)
    的頭像 發(fā)表于 11-13 14:10 ?316次閱讀
    何選擇一個(gè)合適的<b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>來獲得CPU執(zhí)行權(quán)

    Linux線程、線程與異步編程、協(xié)與異步介紹

    協(xié)不是系統(tǒng)級(jí)線程,很多時(shí)候協(xié)被稱為“輕量級(jí)線程”、“微線程”、“纖(fiber)”等。簡(jiǎn)單來說可以認(rèn)為
    的頭像 發(fā)表于 11-11 11:35 ?805次閱讀
    Linux線程、線程與異步編程、<b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>與異步介紹

    協(xié)的實(shí)現(xiàn)與原理

    前言 協(xié)這個(gè)概念很久了,好多程序員是實(shí)現(xiàn)過這個(gè)組件的,網(wǎng)上關(guān)于協(xié)的文章,博客,論壇都是汗牛充棟,在知乎,github上面也有很多大牛寫了關(guān)于協(xié)
    的頭像 發(fā)表于 11-10 10:57 ?349次閱讀

    C/C++協(xié)編程的相關(guān)概念和技巧

    一、引言 協(xié)的定義和背景 協(xié)(Coroutine),又稱為微線程或者輕量級(jí)線程,是一種用戶態(tài)的、可在單個(gè)線程中并發(fā)執(zhí)行的程序組件。協(xié)
    的頭像 發(fā)表于 11-09 11:34 ?530次閱讀

    C++20無棧協(xié)超輕量高性能異步庫(kù)開發(fā)實(shí)戰(zhàn)

    來了,c++標(biāo)準(zhǔn)委員會(huì)的謹(jǐn)慎態(tài)度也造就了c++20的給出來協(xié):“性能之優(yōu)秀”,“開發(fā)之靈活”和讓人勸退的“門檻之高”。 不過話說回來,c++從出身就注定了背負(fù)性能使命,他不是為簡(jiǎn)單為應(yīng)用層維度開發(fā)的語言(如果應(yīng)用層你大可以用pytho
    的頭像 發(fā)表于 11-09 10:20 ?914次閱讀

    協(xié)的作用、結(jié)構(gòu)及原理

    本文介紹了協(xié)的作用、結(jié)構(gòu)、原理,并使用C++和匯編實(shí)現(xiàn)了64位系統(tǒng)下的協(xié)池。文章內(nèi)容避免了協(xié)
    的頭像 發(fā)表于 11-08 16:39 ?963次閱讀
    <b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>的作用、結(jié)構(gòu)及原理

    什么是事件循環(huán)

    Python的Asyncio模塊提供了管理事件、協(xié)、任務(wù)和線程的方法,以及編寫并發(fā)代碼的原語。此模塊的主要組件和概念包括: 事件循環(huán) : 在Asyncio模塊中,每一個(gè)進(jìn)程都有一個(gè)事件循環(huán)。
    的頭像 發(fā)表于 11-01 10:00 ?622次閱讀
    什么是事件循環(huán)

    一文詳解CP15協(xié)處理器

    ARM架構(gòu)通過支持協(xié)處理器來擴(kuò)展處理器的功能。ARM架構(gòu)的處理器支持最多16個(gè)協(xié)處理器,通常稱為CP0~CP15。下述的協(xié)處理器被ARM用于特殊用途。
    發(fā)表于 10-31 16:07 ?1562次閱讀
    一文詳解CP15<b class='flag-5'>協(xié)</b>處理器

    什么是協(xié)?如何徹底理解協(xié)?

    我們先來看一個(gè)普通的函數(shù),這個(gè)函數(shù)非常簡(jiǎn)單
    的頭像 發(fā)表于 10-08 09:58 ?1439次閱讀
    什么是<b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>?如何徹底理解<b class='flag-5'>協(xié)</b><b class='flag-5'>程</b>?

    FreeRTOS任務(wù)與協(xié)介紹

    FreeRTOS 中應(yīng)用既可以使用任務(wù),也可以使用協(xié)(Co-Routine),或者兩者混合使用。但是任務(wù)和協(xié)使用不同的API函數(shù),因此不能通過隊(duì)列(或信號(hào)量)將數(shù)據(jù)從任務(wù)發(fā)送給協(xié)
    的頭像 發(fā)表于 09-28 11:02 ?860次閱讀