執行緒與並行模型

綠色執行緒(green threads)

假設你想要「擁有上百名幫手」的感覺,卻負擔不起雇用並安置上百名真正的員工。於是你只留幾位真正的工人,外加一塊聰明的記事板,讓一位工人能瞬間暫停一位想像幫手的工作、接手另一位的。綠色執行緒就是程式裡那塊記事板:由語言執行期或函式庫在使用者空間建立並排程的執行緒,而不是由作業系統核心,因此你可以用極小的成本擁有大量的它們。

具體來說,綠色執行緒(以及它的近親纖程,fiber)完全在核心之上被管理。執行期保有每條綠色執行緒的堆疊與存好的狀態,並在使用者空間於它們之間切換,不用系統呼叫,這使得建立與切換它們遠比核心執行緒便宜,便宜到可以同時跑數十萬條。因為核心看不到它們,傳統的綠色執行緒落在多對一或多對多模型上。現代系統改良了這個設計:Go 的 goroutine 與類似的輕量任務,在一小池核心執行緒之上跑一個使用者空間排程器(一種 M 對 N 的安排),並與執行期協作,使得一個阻塞操作只停住一個任務、讓另一個去跑。

誠實的取捨源自於不進入核心。在最簡單的(多對一)形式裡,綠色執行緒無法用到一個以上的 CPU 核心,而其中一條的會阻塞系統呼叫可能讓它們全部停擺,這正是使用者層級執行緒的弱點。現代的 M 對 N 執行期把這兩點都修好了,但代價是一個複雜的執行期,它必須攔截阻塞呼叫、並在各核心執行緒之間平衡工作。它的優勢是龐大的規模與便宜的切換,非常適合需要同時應付數萬個大多在等待的任務的程式(網路伺服器);它們並不是純 CPU 密集型平行的免費升級,那種平行最終仍需要多核心上的核心執行緒。

一個聊天伺服器可能需要同時維持十萬條連線開著,其中大多只是在等下一則訊息。產生十萬條核心執行緒會把機器壓垮,但十萬條綠色執行緒(或 goroutine)每條只佔很少記憶體、切換又便宜,所以一個行程就能輕鬆照看它們全部。

數十萬條便宜的使用者空間執行緒,很適合等待,但不是免費的 CPU 倍增器。

傳統的綠色執行緒承襲了使用者層級執行緒的限制:用不到多核心,而且一個阻塞呼叫就可能讓全部凍結。現代的 M 對 N 執行期(如 goroutine)只有靠一個會攔截阻塞、並在各核心執行緒之間分散工作的複雜執行期,才克服這一點。

又稱
fiberslightweight threadsgoroutines (a modern relative)纖程輕量執行緒