新聞中心
Python主線程的問題這里我想在重申一下,對于那些從來沒有學(xué)習過編程或者并非計算機專業(yè)的編程學(xué)習者而言,Python是***的選擇之一,下面文章進行學(xué)習介紹。

站在用戶的角度思考問題,與客戶深入溝通,找到察布查爾錫伯網(wǎng)站設(shè)計與察布查爾錫伯網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:做網(wǎng)站、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、空間域名、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋察布查爾錫伯地區(qū)。
PyThread_acquire_lock有兩種工作方式,通過函數(shù)參數(shù)waitflag來區(qū)分。這個waitflag指示當GIL當前不可獲得時。是否進行等待,更直接地說,就是當前線程是否通過WaitForSingleObject將自身掛起,直到別的線程釋放GIL,然后由操作系統(tǒng)將自己喚醒。
如果waitflag為0,Python會檢查當前GIL是否可用,GIL中的owned是指示GIL是否可用的變量,在前面的InitializeNonRecursiveMutex中我們看到這個值被初始化為-1。Python會檢查這個值是否為-1,如果是,則意味著GIL可用,必須將其置為0,當owned為0后,表示該GIL已經(jīng)被一個線程占用,不再可用。
對于我們這里分析的調(diào)用PyEval_InitThread的主線程而言,由于在初始化GIL之后就調(diào)用PyThread_ acquire_lock申請GIL,到這時,并沒有第二個線程被創(chuàng)建,所以主線程會輕而易舉地獲得GIL的使用權(quán)。
注意這里的檢查和更新owned的操作是通過一個Win32的系統(tǒng)API——Interlocked- CompareExchange——來完成的。這個API是一個原子操作,其函數(shù)原形和功能如下。原形:InterlockedCompareExchange(PLONG dest, long exchange, long compared) 功能:如果*dest == compared,那么*dest = exchange
與InterlockedCompareExchange相同的,InterlockedIncrement也是一個原子操作,其功能是將mutex->owned的值增加1。從這里可以看到,當一個線程開始等待GIL時,其owned就會被增加1。顯然我們可以猜測,當一個線程最終釋放GIL時。
一定會將GIL的owned減1,這樣當所有需要GIL的線程都最終釋放了GIL之后,owned會再次變?yōu)?1,意味著GIL再次變?yōu)榭捎?。為了清晰地展示這一點,我們現(xiàn)在就來看看PyThread_aquire_lock的逆運算,PyThread_release_lock每一個將從運行轉(zhuǎn)態(tài)轉(zhuǎn)為等待狀態(tài)的線程都會在被掛起之前調(diào)用它以釋放對GIL的占有。
最終,一個線程在釋放GIL時,會通過SetEvent通知所有在等待GIL的hevent這個Event內(nèi)核對象的線程,結(jié)合前面的分析。如果這時候有線程在等待GIL的hevent,那么將被操作系統(tǒng)喚醒。這就是我們在前面介紹的Python將線程調(diào)度的第二個難題委托給操作系統(tǒng)來實現(xiàn)的機制。
到了這時,調(diào)用PyEval_InitThread的線程(也就是Python主線程)已經(jīng)成功獲得了GIL,***會調(diào)用PyThread_get_thread_ident()。通過Win32的API:GetCurrent- ThreadId,獲得當前Python主線程的id,并將其賦給main_thread,main_thread是一個靜態(tài)全局變量,專職存儲Python主線程的線程id,用以判斷一個線程是否是Python主線程。
值得注意的是,obj.done是一個Win32下的Semaphore內(nèi)核對象,這個特殊的內(nèi)核對象的用途我們馬上就會看到。我們創(chuàng)建線程的工作需要func和arg,但是Win32下創(chuàng)建線程的API只允許用戶指定一個自定義的參數(shù),這就是需要用obj來打包的原因。
完成打包之后,調(diào)用Win32下創(chuàng)建thread的API:_beginthread來完成線程的創(chuàng)建。奇怪的是,我們期望的線程過程應(yīng)該是thread1.py中定義的那個threadPoc呀,而這里指定的線程過程卻是一個相當面生的bootstrap。實際上,在bootstrap中,會最終調(diào)用thread1.py中定義的threadProc。
現(xiàn)在我們來理清一下Python當前的狀態(tài)。Python主線程當前實際上由兩個Win32下的原生thread構(gòu)成,一個是執(zhí)行python程序(python.exe)時操作系統(tǒng)創(chuàng)建的主線程,另一個是我們通過thread1.py創(chuàng)建的子線程。
主線程在執(zhí)行PyEval_InitThread的過程中,獲得了GIL,但是目前已經(jīng)被掛起,這是為了等待子線程中控制著的obj.done。子線程的線程過程是bootstrap,不過我們剛才已經(jīng)猜測了。
從bootstrap出發(fā),最終將在Python解釋器中執(zhí)行python1.py中定義的theadProc。但是,我們知道,子線程為了訪問Python解釋器,必須首先獲得GIL,這是Python世界的游戲規(guī)則,誰也不能例外。所以,為了避免死鎖,子線程一定會在申請GIL之前通知obj.done。
【編輯推薦】
- 有關(guān)Python系統(tǒng)文件進行介紹指導(dǎo)
- 如何正確的使用Python函數(shù)
- 對Python 構(gòu)建工具進行詳細介紹分析
- PythonAndroid淺析Python優(yōu)勢所在
- 如何使用Python模塊解析配置文件?
本文標題:Python主線程問題進行研究討論
網(wǎng)頁網(wǎng)址:http://m.5511xx.com/article/cdhoehp.html


咨詢
建站咨詢
