python中的協程(yield)內部是怎麼實現的?python和lua在yield的實現原理上有什麼區別?

時間 2021-06-01 01:27:52

1樓:

可能某個yield下呼叫棧是這樣:

main()->resume(Perm)->Perm(list, 3)->Perm(list,2)->Perm(list,1)->yield list

對於Lua來說,程式會從yield直接跳到resume,等下次resume再回到Perm(list, 1)裡面yield。

對於Python來說,程式會一層一層往下走,從1到2到3到resume(Python裡實際是next,性質基本一致),等到下次resume,再一步一步爬回去。

2樓:

程序/執行緒切換需要在核心完成,協程不需要,更加輕量,速度更快。在重 I/O的程式裡有很大的優勢。比如爬蟲裡,開幾百個執行緒會明顯拖慢速度,但是開協程不會。

3樓:馮東

從 @fleuria 的答案說開:

python 的 generator 只保留棧幀上下文,不保留呼叫棧,而且 generator 函式不允許 return;

lua 的 coroutine 保留整個呼叫棧的上下文;

Python 2.x 的 generator 的實現方式是 Lua 5.1 coroutine 在涉及 Lua/C mixed code 時候的 yield 方式。

所以在 Lua 5.1 的時候是不能 yield-from-C 的。不過 Lua 從一開始就可以 resume-from-C,這是因為 Lua 借用了 C runtime stack 作為 coroutine 的 scheduler(具體細節參見《Lua 5.

0 Implementation》)。

從 Lua 5.2 開始,在 Lua C API 裡引入了用顯示宣告 continuation function 的方式來實現 yield-from-C。

Python 3.x 的 generator 借鑑了 Lua 5.2 的 yield-from-C 形式,可以有限的保留呼叫棧上下文。

所以 Python 3.x 的純 Python code coroutine 水平才相當於 Lua 5.2 的 Lua/C mixed code coroutine。

Python 2.x 的 coroutine 和 Lua 的 coroutine 實現相差更遠。

如果你在只有 ANSI C compiler 的平台上做 script/C hybrid 開發,Lua coroutine 是唯一的選擇了。

4樓:fleuria

python 的 generator 只保留棧幀上下文,不保留呼叫棧,而且 generator 函式不允許 return;

lua 的 coroutine 保留整個呼叫棧的上下文;

5樓:

對Python來說,題主可以了解一下CPython和Stackless Python。

大致查了一下,python的yield貌似是用底層虛擬機器的棧狀態切換來實現,看了下lua的programming in lua那本書,裡面的coroutine貌似是用執行緒來切換。是否可以理解為python的coroutine是用單執行緒的方式,而lua是用多執行緒方式來實現協程的?

題主指的應該是CPython,CPython的yield實現是基於棧和Frame的,Frame是乙個CPython虛擬機器中的乙個模擬棧幀的物件。yield對應CPython中的乙個生成器物件,檔案在這裡:

cpython: b3f4616b9a94 Objects/genobject.c

yield在虛擬機器中對應的是乙個操作碼,相應會執行一串CPython虛擬機器位元組碼,如果明白yield會生成乙個物件,那麼其實很好理解,乙個物件的狀態儲存和切換使用一些屬性來做,在虛擬機器中很好實現。CPython的yield的確是單執行緒,或者說,其實CPython把yield和對應的生成器只是轉化為一段位元組碼,CPython虛擬機器的位元組碼執行是單執行緒的。

Lua的實現更類似於很多流行的協程庫的實現,使用C中的setjmp和longjmp,使用乙個排程器排程執行緒組,儲存和切換上下文,大部分協程的實現,其實就是實現乙個執行緒排程器。

6樓:

lua底層實現上還是單執行緒的,只是lua中的每個coroutine都有乙個自帶的呼叫棧。只是你手動呼叫時底層執行緒的指標指向了coroutine的棧,退出時指回原來的地方,俗稱還原現場。大概是這樣的,沒深入了解過lua,逃。

或者可以搜一下「纖程」,更或者搜「c++實現協程」等等,這樣你對底層的了解會更多。

7樓:劉瀚陽

lua裡面:當resume的時候,就切換lua_state環境,然後setjmp,緊接著由於pc指向新位址,所以會直接跳轉到該位置;

當yield時,直接回覆環境,然後longjmp到該resume點

lua with C:當在C函式內入yield時,會恢復環境,longjmp到resume點,之後再次resume的時候,會因為環境被破壞,導致resume出錯,此時lua會呼叫k系列函式,讓resume繼續下去

python協程是什麼?

雞蛋有點黃 協程和程序的區別其他答案都寫的很好了,我就是複製一下流暢的python書中對執行緒和協程的比較說明 如果使用執行緒做過重要的程式設計,你就知道寫 出程式有多麼困難,因為排程程式任何時候都能中斷執行緒。必須記住保留鎖,去保護程式 中的重要部分,防止多步操作在執行的過程中中斷,防止資料處於無...

PHP的協程跟GO的協程實現有什麼區別?

Shulamith 黑色高階車和白色低階車的區別 swoole那個基本上就是最常見的有棧協程的實現,各種語言社群裡一抓一大把,主要作用是給只會 只能用PHP的程式設計師打雞血.go的實現則比較高階,主要優勢在於 跑在多個系統執行緒上,可以充分利用多核 讓出執行權的節點不只是io,還有函式呼叫 xtl...

PHP 的協程化是什麼意思?

沒啥複雜的東西。磁碟IO,網路IO一般都是同步阻塞的。像你上述提到的三個類庫,都是網路IO,一般情況下都是同步阻塞的方式。1.並不是 協程化 之後才能用 不修改,同步阻塞操作會阻塞整個程序,能處理的併發請求就少了,就失去了使用協程的初衷了。2.第三方類庫一般都設計的很好,只要自定義乙個handler...