python 代碼的執(zhí)行由python虛擬機(jī)來控制,虛擬機(jī)訪問由GIL控制,保證其同一時(shí)刻只有一條線程運(yùn)行。
雖然python能運(yùn)行多線程,但是因?yàn)镚IL所以同一時(shí)刻只有一條線程在python解釋器運(yùn)行。
?
多線程下python虛擬機(jī)按以下方式執(zhí)行:
1. 設(shè)置GIL
2. 切換到一條線程去運(yùn)行
3. 運(yùn)行:
a. 執(zhí)行python2虛擬機(jī)運(yùn)行1000字節(jié)指令? ? 或者? ? 執(zhí)行python3虛擬機(jī)運(yùn)行時(shí)間15ms字節(jié)
b. 線程主動(dòng)讓出控制(遭遇sleep或者IO操作也將觸發(fā))
4. 把線程設(shè)置為睡眠狀態(tài)(等待狀態(tài))
5. 釋放GIL
6. 再次重復(fù)上述操作
?
線程何時(shí)切換?
==========================================================
(1)一個(gè)線程無論何時(shí)開始睡眠或等待網(wǎng)絡(luò) I/O,其他線程總有機(jī)會(huì)獲取 GIL 執(zhí)行 Python 代碼。這是協(xié)同式多任務(wù)處理。CPython 也還有搶占式多任務(wù)處理。如果一個(gè)線程不間斷地在 Python 2 中運(yùn)行 1000 字節(jié)碼指令,或者不間斷地在 Python 3 運(yùn)行15 毫秒,那么它便會(huì)放棄 GIL,而其他線程可以運(yùn)行。把這想象成有多個(gè)線程但只有一個(gè) CPU 時(shí)的時(shí)間片可用。
(2)當(dāng)執(zhí)行C/C++代碼時(shí)候,直到C函數(shù)執(zhí)行完畢,才讓出GIL。
?
讓我們回顧下 Python 是如何運(yùn)行的。你的程序分兩個(gè)階段運(yùn)行。首先,Python文本被編譯成一個(gè)名為字節(jié)碼的簡(jiǎn)單二進(jìn)制格式。第二,Python解釋器的主回路,一個(gè)名叫 pyeval_evalframeex() 的函數(shù),流暢地讀取字節(jié)碼,逐個(gè)執(zhí)行其中的指令。
搶占式多任務(wù)處理
當(dāng)解釋器通過字節(jié)碼時(shí),它會(huì)定期放棄GIL,而不需要經(jīng)過正在執(zhí)行代碼的線程允許,這樣其他線程便能運(yùn)行:默認(rèn)情況下,檢測(cè)間隔是1000 字節(jié)碼。所有線程都運(yùn)行相同的代碼,并以相同的方式定期從他們的鎖中抽出。在 Python 3 GIL 的實(shí)施更加復(fù)雜,檢測(cè)間隔不是一個(gè)固定數(shù)目的字節(jié)碼,而是15 毫秒。然而,對(duì)于你的代碼,這些差異并不顯著。
協(xié)同式多任務(wù)處理
當(dāng)一項(xiàng)任務(wù)比如網(wǎng)絡(luò) I/O啟動(dòng),而在長(zhǎng)的或不確定的時(shí)間,沒有運(yùn)行任何 Python 代碼的需要,一個(gè)線程便會(huì)讓出GIL,從而其他線程可以獲取 GIL 而運(yùn)行 Python。
這種禮貌行為稱為協(xié)同式多任務(wù)處理,它允許并發(fā);多個(gè)線程同時(shí)等待不同事件。多個(gè)線程在同一時(shí)刻只能有一個(gè)執(zhí)行 Python ,但一旦線程開始連接,它就會(huì)放棄 GIL ,這樣其他線程就可以運(yùn)行。這意味著多個(gè)線程可以并發(fā)等待套接字連接,這是一件好事。在同樣的時(shí)間內(nèi)它們可以做更多的工作。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
