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

對(duì)Python應(yīng)用線程介紹說(shuō)明

開發(fā) 后端
下面的文章主要介紹一下有關(guān)Python應(yīng)用線程的問(wèn)題,那么,Python為什么需要讓Python應(yīng)用線程等待子線程的通知了。呢。

Python中提供的一些接口中,一定不能少的肯定是創(chuàng)建Python應(yīng)用線程的接口,倘若沒有這個(gè)接口,編程還有什么太多的意義啊,對(duì)多線程的支持并非是沒有代價(jià)的。

我們注意到boot->interp中保存了Python的PyInter- preterState對(duì)象,這個(gè)對(duì)象中攜帶了Python的module pool這樣的全局信息,Python中所有的thread都會(huì)共享這些全局信息。關(guān)于代碼清單所示的多線程環(huán)境的初始化動(dòng)作。

有一點(diǎn)需要特別說(shuō)明,當(dāng)Python啟動(dòng)時(shí),是并不支持多線程的。換句話說(shuō),Python中支持多線程的數(shù)據(jù)結(jié)構(gòu)以及GIL都是沒有創(chuàng)建的,Python之所以有這種行為是因?yàn)榇蠖鄶?shù)的Python應(yīng)用線程都不需要多線程的支持。

假如一個(gè)簡(jiǎn)單地統(tǒng)計(jì)詞頻的Python腳本中居然出現(xiàn)了多線程,面對(duì)這樣的代碼,我們一定都會(huì)抓狂的J。對(duì)多線程的支持并非是沒有代價(jià)的。最簡(jiǎn)單的一點(diǎn),如果激活多線程機(jī)制,而執(zhí)行的Python程序中并沒有多線程,那么在100條指令之后,Python虛擬機(jī)同樣會(huì)激活線程的調(diào)度。

而如果不激活多線程,Python虛擬機(jī)則不用做這些無(wú)用功。所以Python選擇了讓用戶激活多線程機(jī)制的策略。在Python虛擬機(jī)啟動(dòng)時(shí),多線程機(jī)制并沒有被激活,它只支持單線程,一旦用戶調(diào)用thread.start_new_thread。

明確指示Python虛擬機(jī)創(chuàng)建新的線程,Python就能意識(shí)到用戶需要多線程的支持,這個(gè)時(shí)候,Python虛擬機(jī)會(huì)自動(dòng)建立多線程機(jī)制需要的數(shù)據(jù)結(jié)構(gòu)、環(huán)境以及那個(gè)至關(guān)重要的GIL。

在這里,我們終于看到了Python中多線程機(jī)制的平臺(tái)相關(guān)性,在Python25\Python目錄下,有一大批thread_***.h這樣的文件。在這些文件中,包裝了不同操作系統(tǒng)的原生線程,并通過(guò)統(tǒng)一的接口暴露給Python,比如這里的PyThread_allocate_lock就是這樣一個(gè)接口。

我們這里的thread_nt.h中包裝的是Win32平臺(tái)的原生thread,在本章中后面的代碼剖析中,還會(huì)有大量與平臺(tái)相關(guān)的代碼,我們都以Win32平臺(tái)為例。在PyThread_allocate_lock中,與PyEval_InitThreads非常類似的,它會(huì)檢查一個(gè)initialized的變量,如果說(shuō)GIL指示著Python的多線程環(huán)境是否已經(jīng)建立。

那么這個(gè)initialized變量就指示著為了使用底層平臺(tái)所提供的原生thread,必須的初始化動(dòng)作是否完成。這些必須的初始化動(dòng)作通常都是底層操作系統(tǒng)所提供的API,不同的操作系統(tǒng)可能需要不同的初始化動(dòng)作。

一切真相大白了,原來(lái),GIL(NRMUTEX)中的hevent就是Win32平臺(tái)下的Event這個(gè)內(nèi)核對(duì)象,而其中的thread_id將記錄任一時(shí)刻獲得GIL的線程的id。到了這里,Python中的線程互斥機(jī)制的真相漸漸浮出水面。

看來(lái)Python應(yīng)用線程是通過(guò)Win32下的Event來(lái)實(shí)現(xiàn)了線程的互斥,熟悉Win32的朋友馬上就可能想到,與這個(gè)Event對(duì)應(yīng)的,必定有一個(gè)WaitForSingleObject。在PyEval_InitThreads通過(guò)PyThread_allocate_lock成功地創(chuàng)建了GIL之后,當(dāng)前線程就開始遵循Python的多線程機(jī)制的規(guī)則:

在調(diào)用任何Python C API之前,必須首先獲得GIL。因此PyEval_InitThreads緊接著通過(guò)PyThread_acquire_lock嘗試獲得GIL。最終,一個(gè)線程在釋放GIL時(shí),會(huì)通過(guò)SetEvent通知所有在等待GIL的hevent這個(gè)Event內(nèi)核對(duì)象的線程,結(jié)合前面的分析。

如果這時(shí)候有線程在等待GIL的hevent,那么將被操作系統(tǒng)喚醒。這就是我們?cè)谇懊娼榻B的Python將線程調(diào)度的第二個(gè)難題委托給操作系統(tǒng)來(lái)實(shí)現(xiàn)的機(jī)制。到了這時(shí),調(diào)用PyEval_InitThread的線程(也就是Python主線程)已經(jīng)成功獲得了GIL,最后會(huì)調(diào)用PyThread_get_thread_ident()。

通過(guò)Win32的API:GetCurrent- ThreadId,獲得當(dāng)前Python主線程的id,并將其賦給main_thread,main_thread是一個(gè)靜態(tài)全局變量。專職存儲(chǔ)Python主線程的線程id,用以判斷一個(gè)線程是否是Python主線程。最后,我們?cè)诮o出整個(gè)PyEval_InitThread的函數(shù)調(diào)用關(guān)系。

值得注意的是,obj.done是一個(gè)Win32下的Semaphore內(nèi)核對(duì)象,這個(gè)特殊的內(nèi)核對(duì)象的用途我們馬上就會(huì)看到。我們創(chuàng)建線程的工作需要func和arg,但是Win32下創(chuàng)建線程的API只允許用戶指定一個(gè)自定義的參數(shù),這就是需要用obj來(lái)打包的原因。

完成打包之后,調(diào)用Win32下創(chuàng)建thread的API:_beginthread來(lái)完成線程的創(chuàng)建。奇怪的是,我們期望的線程過(guò)程應(yīng)該是thread1.py中定義的那個(gè)threadPoc呀,而這里指定的線程過(guò)程卻是一個(gè)相當(dāng)面生的bootstrap。實(shí)際上,在bootstrap中,會(huì)最終調(diào)用thread1.py中定義的threadProc。

但是,這里有一個(gè)至關(guān)重要的轉(zhuǎn)折,還記得我們現(xiàn)在在哪里嗎?沒錯(cuò),我們現(xiàn)在是沿著主線程的執(zhí)行路徑在剖析,而對(duì)bootstrap的調(diào)用并不是在主線程中發(fā)生的,而是在通過(guò)_beginthread所創(chuàng)建的子線程中發(fā)生的。從這里開始,我們需要特別注意代碼的執(zhí)行是在哪個(gè)線程中執(zhí)行的,這對(duì)于理解Python應(yīng)用線程機(jī)制相當(dāng)重要。

好了,花開兩朵,各表一枝。我們繼續(xù)沿著主線程的執(zhí)行路徑前進(jìn)。如果不出什么意外,_beginthread將最終成功地創(chuàng)建Win32下的原生線程,并順利返回。在返回之后,主線程開始將自己掛起,等待obj.done。

我們前面看到,這是一個(gè)Win32的Semaphore內(nèi)核對(duì)象。由于obj已經(jīng)作為參數(shù)傳遞給了子線程,所以我們猜想,子線程會(huì)設(shè)置這個(gè)Semaphore,并最終喚醒主線程?,F(xiàn)在我們來(lái)理清一下Python當(dāng)前的狀態(tài)。

Python當(dāng)前實(shí)際上由兩個(gè)Win32下的原生thread構(gòu)成,一個(gè)是執(zhí)行python程序(python.exe)時(shí)操作系統(tǒng)創(chuàng)建的主線程,另一個(gè)是我們通過(guò)thread1.py創(chuàng)建的子線程。主線程在執(zhí)行PyEval_InitThread的過(guò)程中。

得了GIL,但是目前已經(jīng)被掛起,這是為了等待子線程中控制著的obj.done。子線程的線程過(guò)程是bootstrap,不過(guò)我們剛才已經(jīng)猜測(cè)了,從bootstrap出發(fā),最終將在Python解釋器中執(zhí)行python1.py中定義的theadProc。但是,我們知道,子線程為了訪問(wèn)Python解釋器,必須首先獲得GIL,這是Python世界的游戲規(guī)則,誰(shuí)也不能例外。

【編輯推薦】

  1. 漫談Python 源代碼編制技巧
  2. 簡(jiǎn)單易于操作的Python 工具詳解
  3. 有關(guān)Python應(yīng)用領(lǐng)域進(jìn)行說(shuō)明介紹
  4. PythonAndroid面向?qū)ο蟮木幊獭狿ython應(yīng)用程序
  5. 如何使用Python模塊解析配置文件 ?
責(zé)任編輯:chenqingxiang 來(lái)源: CSDN
相關(guān)推薦

2010-02-02 14:42:38

Python線程

2010-02-02 13:28:46

Python變量

2010-02-22 11:14:43

Python編寫

2010-02-26 13:56:08

Python RSS

2010-02-26 10:07:55

Python編程語(yǔ)言

2010-02-24 16:44:58

Python 函數(shù)

2010-02-22 17:46:57

Python應(yīng)用程序

2010-02-26 09:42:52

Python線程池

2009-12-08 16:09:02

WCF消息

2009-12-21 10:01:05

Oracle技術(shù)

2010-01-25 18:19:17

C++特性

2010-01-25 18:19:17

C++特性

2010-01-25 18:19:17

C++特性

2010-02-26 11:20:53

Python應(yīng)用

2010-02-26 10:55:53

Python系統(tǒng)程序

2009-12-14 17:44:39

Visual Stud

2010-01-14 13:39:45

Visual C++優(yōu)

2010-01-15 19:34:25

C++設(shè)計(jì)

2010-02-22 14:54:47

Python應(yīng)用程序

2010-03-02 11:12:33

Android應(yīng)用開發(fā)
點(diǎn)贊
收藏

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