一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Python 協程與 JavaScript 協程的對比

Python 協程與 JavaScript 協程的對比

2022-01-06 12:54 Python

當漸漸對 JavaScript 了解后,一查發現 Python 和 JavaScript 的協程發展史簡直就是一毛一樣!接下來小編就大致做下橫向對比和總結,便于對這兩個語言有興趣的新人理解和吸收。

Python 協程與 JavaScript 協程的對比

1、前言

  • 隨著 cpu 多核化,都需要實現由于自身歷史原因(單線程環境)下的并發功能
  • 簡化代碼,避免回調地獄,關鍵字支持
  • 有效利用操作系統資源和硬件:協程相比線程,占用資源更少,上下文更快

2、什么是協程?

總結一句話,協程就是滿足下面條件的函數:

  •  可以暫停執行(暫停的表達式稱為暫停點)
  •  可以從掛起點恢復(保留其原始參數和局部變量)
  •  事件循環是異步編程的底層基石

3、混亂的歷史

3.1 Python 協程的進化

  • Python2.2 中,第一次引入了生成器
  • Python2.5 中,yield 關鍵字被加入到語法中
  • Python3.4 時有了 yield fromyield from 約等于 yield + 異常處理 + send), 并試驗性引入的異步 I/O 框架 asyncio(PEP 3156)
  • Python3.5 中新增了 async/await 語法(PEP 492)
  • Python3.6 中 asyncio 庫"轉正" (之后的官方文檔就清晰了很多)

在主線發展過程中,也出現了很多支線的協程實現如 Gevent。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 
foo a a 
foo start 
foo start 
foo start 
foo a None 
foo end 
"""

4、JavaScript 協程的進化

  • 同步代碼
  • 異步 JavaScript: callback hell
  • ES6 引入 Promise/a+, 生成器 Generators(語法 function foo(){}* 可以賦予函數執行暫停/保存上下文/恢復執行狀態的功能), 新關鍵詞 yield 使生成器函數暫停。
  • ES7 引入 async函數/await語法糖,async 可以聲明一個異步函數(將 Generator 函數和自動執行器,包裝在一個函數里),此函數需要返回一個 Promise 對象。await 可以等待一個 Promise 對象 resolve,并拿到結果

Promise 中也利用了回調函數。在 then catch 方法中都傳入了一個回調函數,分別在 Promise 被滿足和被拒絕時執行,這樣就就能讓它能夠被鏈接起來完成一系列任務。

總之就是把層層嵌套的 callback 變成 .then().then()...,從而使代碼編寫和閱讀更直觀。

生成器 Generator 的底層實現機制是協程 Coroutine。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 
foo a undefined 
foo start 
foo start 
*/

5、Python 協程成熟體

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

5.1 協程(coroutine)

  • 協程函數:定義形式為 async def 的函數;
  • 協程對象:調用 協程函數 所返回的對象
  • 舊式基于 generator(生成器)的協程

5.2 任務(Task 對象)

  • 任務 被用來“并行的”調度協程, 當一個協程通過 asyncio.create_task() 等函數被封裝為一個 任務,該協程會被自動調度執行
  • Task 對象被用來在事件循環中運行協程。如果一個協程在等待一個 Future 對象,Task 對象會掛起該協程的執行并等待該 Future 對象完成。當該 Future 對象 完成,被打包的協程將恢復執行。
  • 事件循環使用協同日程調度: 一個事件循環每次運行一個 Task 對象。而一個 Task 對象會等待一個 Future 對象完成,該事件循環會運行其他 Task、回調或執行 IO 操作。
  • asyncio.Task Future 繼承了其除 Future.set_result() Future.set_exception() 以外的所有 API。

5.3 未來對象(Future)

 Future 對象用來鏈接 底層回調式代碼 和高層異步/等待式代碼。
 不用回調方法編寫異步代碼后,為了獲取異步調用的結果,引入一個 Future 未來對象。Future 封裝了與 loop 的交互行為,add_done_callback 方法向 epoll 注冊回調函數,當 result 屬性得到返回值后,會運行之前注冊的回調函數,向上傳遞給 coroutine

5.4幾種事件循環(event loop)

  • libevent/libev:Gevent(greenlet + 前期 libevent,后期 libev)使用的網絡庫,廣泛應用;
  •  tornado:tornado 框架自己實現的 IOLOOP;
  •  picoev:meinheld(greenlet+picoev)使用的網絡庫,小巧輕量,相較于 libevent 在數據結構和事件檢測模型上做了改進,所以速度更快。但從 github 看起來已經年久失修,用的人不多。
  •  uvloop:Python3 時代的新起之秀。Guido 操刀打造了 asyncio 庫,asyncio 可以配置可插拔的event loop,但需要滿足相關的 API 要求,uvloop 繼承自 libuv,將一些低層的結構體和函數用 Python 對象包裝。目前 Sanic 框架基于這個庫

例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 本質是一個狀態機,用于表示一個異步操作的最終完成 (或失敗), 及其結果值。它有三個狀態:

  •  pending: 初始狀態,既不是成功,也不是失敗狀態。
  •  fulfilled: 意味著操作成功完成。
  •  rejected: 意味著操作失敗。

最終 Promise 會有兩種狀態,一種成功,一種失敗,當 pending 變化的時候,Promise 對象會根據最終的狀態調用不同的處理函數。

6.2 async、await語法糖

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

6.3 js 異步執行的運行機制

  • 所有任務都在主線程上執行,形成一個執行棧。
  •  主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。
  •  一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列"。那些對應的異步任務,結束等待狀態,進入執行棧并開始執行。

遇到同步任務直接執行,遇到異步任務分類為宏任務(macro-task)和微任務(micro-task)。

當前執行棧執行完畢時會立刻先處理所有微任務隊列中的事件,然后再去宏任務隊列中取出一個事件。同一次事件循環中,微任務永遠在宏任務之前執行。

例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 同步執行的代碼塊,setTimeout、setIntervalXMLHttprequestsetImmediate、I/O、UI rendering等,本質是參與了事件循環的任務
微隊列(micro task)Promise、process.nextTick(node環境)、Object.observe, MutationObserver等,本質是直接在 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 協程內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://developer.51cto.com/art/202109/682489.htm

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 美女黄金大片视频免费看 | 欧美一区二区三区成人看不卡 | 欧美不卡一区二区三区免 | 美女被草逼 | 亚洲精品动漫在线观看 | 人人人人人看碰人人免费 | 免费观看日本 | 暖暖日本在线观看免费 | 色多多多 | www在线视频在线播放 | a级成人毛片免费图片 | freesex1718处xx| 高清色黄毛片一级毛片 | 手机看片一区二区 | 国产精品久久国产精品99盘 | 国产精品极品 | 亚洲国产成人久久77 | 波多野结衣久久国产精品 | 国产午夜久久精品 | ai换脸明星专区在线观看 | 日本漫画无翼乌 | 国产午夜精品一区二区三区不卡 | 国产在线精品一区二区高清不卡 | 久久爽狠狠添AV激情五月 | 我与么公激情性完整视频 | 色综合亚洲精品激情狠狠 | 久久免费国产视频 | α片免费 | 黑人巨大爆粗亚裔女人 | 公共场合高h短篇 | 久久99影院 | 国产资源一区 | 国产色在线观看 | 免费在线影院 | 日本69av | 91sao国产在线观看 | 四虎精品永久免费 | 美女靠逼免费视频 | 日韩精品一区二区三区老鸭窝 | 1769在线视频 | 亚洲精选在线观看 |