自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文弄懂 Gunicorn 與 Python GIL

開發(fā) 前端
Python 和 Gunicorn 為您提供了處理并發(fā)的不同方法,并且由于沒有涵蓋所有用例的靈丹妙藥,因此最好了解每個選項的選項、權(quán)衡和優(yōu)勢。

什么是 Python GIL,它是如何工作的,以及它如何影響 gunicorn。

生產(chǎn)環(huán)境我應(yīng)該選擇哪種 Gunicorn worker類型?

Python 有一個全局鎖 (GIL),它只允許一個線程運行(即解釋字節(jié)碼)。在我看來,如果你想優(yōu)化你的 Python 服務(wù),理解 Python 如何處理并發(fā)是必不可少的。

Python 和 gunicorn 為您提供了處理并發(fā)的不同方法,并且由于沒有涵蓋所有用例的靈丹妙藥,因此最好了解每個選項的選項、權(quán)衡和優(yōu)勢。

Gunicorn worker類型

Gunicorn 以“workers types”的概念公開了這些不同的選項。每種類型都適用于一組特定的用例。

  • sync——將進程分叉成 N 個并行運行的進程來處理請求。
  • gthread——產(chǎn)生 N 個線程來并發(fā)服務(wù)請求。
  • eventlet/gevent——產(chǎn)生綠色線程來并發(fā)服務(wù)請求。

Gunicorn sync worker

這是最簡單的工作類型,其中唯一的并發(fā)選項是分叉N個進程,它們將并行地服務(wù)請求。

它們可以很好地工作,但會招致大量開銷(例如內(nèi)存和CPU上下文切換),而且如果您的大部分請求時間都在等待I/O,那么伸縮性就不好。

Gunicorn gthread worker

gthread worker 通過允許您為每個進程創(chuàng)建 N 個線程來改進這一點。這提高了 I/O 性能,因為您可以同時運行更多代碼實例。這是受 GIL 影響的四個中唯一一個。

Gunicorn eventlet and gevent workers

eventlet/gevent workers試圖通過運行輕量級用戶線程(又名綠色線程、greenlets 等)來進一步改進 gthread 模型。

與系統(tǒng)線程相比,這允許您以很少的成本擁有數(shù)千個所述的greenlet。 另一個區(qū)別是它遵循協(xié)作工作模型而不是搶占式,允許不間斷工作,直到它們阻塞為止。我們將首先分析 gthread 工作線程在處理請求時的行為以及它如何受 GIL 影響。

與每個請求直接由一個進程提供服務(wù)的sync不同,使用 gthread,每個進程都有 N 個線程,以便更好地擴展,而無需產(chǎn)生多個進程的開銷。由于您在同一個進程中運行多個線程,GIL 將阻止它們并行運行。

GIL 不是進程或特殊線程。它只是一個布爾變量,其訪問受互斥鎖保護,用于確保每個進程內(nèi)只有一個線程在運行。它的工作方式可以在上圖中看到。在這個例子中,我們可以看到我們有 2 個系統(tǒng)線程并發(fā)運行,每個線程處理 1 個請求。流程是這樣的:

  • 線程 A 持有 GIL 開始服務(wù)請求。
  • 過了一會兒,線程 B 嘗試提供請求,但無法持有 GIL。
  • B 設(shè)置超時以強制釋放 GIL,如果在達到超時之前不會發(fā)生這種情況。
  • A 在達到超時之前不會釋放 GIL。
  • B 設(shè)置 gil_drop_request 標志以強制 A 立即釋放 GIL。
  • A 釋放 GIL 并將等待直到另一個線程抓取 GIL,以避免出現(xiàn) A 會不斷釋放并抓取 GIL 而其他線程無法抓取它的情況。
  • B 開始運行。
  • B 在阻塞 I/O 的同時釋放 GIL。
  • A 開始運行。
  • B 嘗試再次運行但被暫停。
  • A 在達到超時之前完成。
  • B 運行完畢。

相同的場景,但使用 gevent

?圖片

在不使用進程的情況下增加并發(fā)性的另一個選擇是使用 greenlets。該worker產(chǎn)生“用戶線程”而不是“系統(tǒng)線程”以增加并發(fā)性。

盡管這意味著它們不受 GIL 的影響,但這也意味著您仍然無法增加并行度,因為它們無法由 CPU 并行調(diào)度。

  • Greenlet A將開始運行,直到發(fā)生I/O事件或執(zhí)行完畢。
  • Greenlet B將等待直到Greenlet A釋放事件循環(huán)。
  • A結(jié)束。
  • B開始。
  • B釋放事件循環(huán)以等待I/O。
  • B完成。

對于這種情況,很明顯,擁有一個 greenlet 類型的worker并不理想。我們最終讓第二個請求等到第一個請求完成,然后再次空閑等待 I/O。

在這些場景中,greenlet 協(xié)作模型真的很出色,因為您不會在上下文切換上浪費時間并避免運行多個系統(tǒng)線程的開銷。

我們將在本文末尾的基準測試中見證這一點。現(xiàn)在,這引出了以下問題:

  • 更改線程上下文切換超時是否會影響服務(wù)延遲和吞吐量?
  • 當您混合使用 I/O 和 CPU 工作時,如何在 gevent/eventlet 和 gthread 之間進行選擇。
  • 如何使用 gthread worker 選擇線程數(shù)。
  • 我應(yīng)該只使用sync worker并增加分叉進程的數(shù)量來避免 GIL 嗎?

要回答這些問題,您需要進行監(jiān)控以收集必要的指標,然后針對這些相同的指標運行量身定制的基準測試。運行與您的實際使用模式零相關(guān)性的綜合基準測試是沒有用的 下圖顯示了不同場景的延遲和吞吐量指標,讓您了解這一切是如何協(xié)同工作的。

對 GIL 切換間隔進行基準測試

圖片在這里我們可以看到更改 GIL 線程切換間隔/超時如何影響請求延遲。正如預(yù)期的那樣,IO 延遲隨著切換間隔的降低而變得更好。發(fā)生這種情況是因為受 CPU 限制的線程被迫更頻繁地釋放 GIL 并允許其他線程完成它們的工作。

但這不是靈丹妙藥。減少切換間隔將使 CPU 綁定線程需要更長的時間才能完成。我們還可以看到總延遲增加,由于恒定線程切換的開銷增加,超時時間減少。如果您想自己嘗試,可以使用以下代碼更改切換間隔:

圖片

使用 CPU 綁定請求對 gthread 與 gevent 延遲進行基準測試

圖片

總的來說,我們可以看到基準測試反映了我們之前對 GIL 綁定線程和 greenlet 如何工作的分析所產(chǎn)生的直覺。

由于切換間隔迫使長時間運行的線程釋放,gthread 對于 IO 綁定請求具有更好的平均延遲。

gevent CPU 綁定請求比 gthread 具有更好的延遲,因為它們不會被中斷以服務(wù)其他請求。

使用 CPU 綁定請求對 gthread 與 gevent 吞吐量進行基準測試

圖片

這里的結(jié)果也反映了我們之前對 gevent 比 gthread 具有更好吞吐量的直覺。這些基準高度依賴于完成的工作類型,不一定直接轉(zhuǎn)化為您的用例。

這些基準測試的主要目標是為您提供一些有關(guān)測試和測量內(nèi)容的指南,以便最大限度地提高將服務(wù)于請求的每個 CPU 內(nèi)核。

由于所有 gunicorn worker 都允許您指定將運行的進程數(shù),因此更改的是每個進程如何處理并發(fā)連接。因此,請確保使用相同數(shù)量的worker以使測試公平。現(xiàn)在讓我們嘗試使用從我們的基準測試中收集的數(shù)據(jù)來回答前面的問題。

更改線程上下文切換超時是否會影響服務(wù)延遲和吞吐量?

 確實如此。然而,對于絕大多數(shù)工作負載來說,它并沒有改變游戲規(guī)則。

當您混合使用 I/O 和 CPU 工作時,如何在 gevent/eventlet 和 gthread 之間進行選擇? 正如我們所看到的,當您有更多 CPU 密集型工作時,ghtread 往往允許更好的并發(fā)性。

如何選擇gthread worker的線程數(shù)?

只要您的基準測試能夠模擬類似生產(chǎn)的行為,您就會清楚地看到峰值性能,然后它會因線程過多而開始下降。

我應(yīng)該只使用同步工作者并增加分叉進程的數(shù)量來避免 GIL 嗎?

除非您的 I/O 幾乎為零,否則僅使用進程進行擴展并不是最佳選擇。

結(jié)論

Coroutines/Greenlets 可以提高 CPU 效率,因為它們避免了線程之間的中斷和上下文切換。協(xié)程用延遲換取吞吐量。

如果您混合使用 IO 和 CPU 綁定端點,協(xié)程可能會導(dǎo)致更難以預(yù)測的延遲——CPU 綁定端點不會被中斷以服務(wù)其他傳入請求。如果您花時間正確配置 gunicorn,GIL 不是問題。

責(zé)任編輯:姜華 來源: 新鈦云服
相關(guān)推薦

2022-08-09 09:10:43

Kubernetes容器

2023-11-28 09:31:55

MySQL算法

2023-09-18 08:02:45

CSS布局屬性

2023-10-26 16:27:50

前端 WebCSS開發(fā)

2023-12-12 07:31:51

Executors工具開發(fā)者

2024-05-09 10:11:30

2024-04-02 09:38:21

PythonGIL

2023-04-04 08:01:47

2023-03-30 08:52:40

DartFlutter

2022-09-05 09:25:53

KubernetesService

2023-03-27 17:58:34

MySQL加鎖間隙鎖

2021-06-02 05:43:36

比特幣虛擬貨幣區(qū)塊鏈

2022-08-03 08:01:16

CDN網(wǎng)站服務(wù)器

2022-01-04 08:54:32

Redis數(shù)據(jù)庫數(shù)據(jù)類型

2024-10-16 10:11:52

2022-09-09 10:00:13

KubernetesConfigMap

2021-12-20 07:59:07

Go語言結(jié)構(gòu)體

2020-10-14 10:21:02

算法算法思想數(shù)據(jù)

2022-02-23 08:55:06

數(shù)據(jù)遷移分庫分表數(shù)據(jù)庫

2024-02-23 19:11:13

C++編程開發(fā)
點贊
收藏

51CTO技術(shù)棧公眾號