如何創新Python虛擬機線程
一些開發人員明確指示Python虛擬機創建新的線程,Python就能意識到用戶需要多線程的支持,如果沒有前期的這些支持,不知道Python虛擬機能不能順利的發展下去。
Python虛擬機的thread module所提供的接口中,一定不能少的肯定是創建線程的接口,倘若沒有這個接口,生活還有什么意義呢J?在上面的thread1.py中,我們正是通過其提供的start_new_thread創建了一個嶄新的線程。好,我們就進入這個start_new_ thread,看看Python是如何進行創世紀的工作的:
- [thread_nt.h]
- int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
- {
- int success ;
- success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag
- == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ;
- return success;
- }
- DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
- {
- /* Assume that the thread waits successfully */
- DWORD ret;
- /* InterlockedIncrement(&mutex->owned) == 0 means that no thread
- currently owns the mutex */
- if (!wait)
- {
- if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0,
- (PVOID)-1) != (PVOID)-1)
- return WAIT_TIMEOUT ;
- ret = WAIT_OBJECT_0 ;
- }
- else
- ret = InterlockedIncrement(&mutex->owned) ?
- /* Some thread owns the mutex, let's wait... */
- WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
- mutex->thread_id = GetCurrentThreadId() ; /* We own it */
- return ret ;
- }
在代碼清單中,我們注意到boot->interp中保存了Python的PyInter- preterState對象,這個對象中攜帶了Python的module pool這樣的全局信息,Python中所有的thread都會共享這些全局信息。
關于代碼清單15-1的[2]處所示的多線程環境的初始化動作,有一點需要特別說明,當Python啟動時,是并不支持多線程的。換句話說,Python中支持多線程的數據結構以及GIL都是沒有創建的,Python之所以有這種行為是因為大多數的Python程序都不需要多線程的支持。
假如一個簡單地統計詞頻的Python腳本中居然出現了多線程,面對這樣的代碼,我們一定都會抓狂的J。
對多線程的支持并非是沒有代價的。最簡單的一點,如果激活多線程機制,而執行的Python程序中并沒有多線程,那么在100條指令之后,Python虛擬機同樣會激活線程的調度。
而如果不激活多線程,Python虛擬機則不用做這些無用功。所以Python選擇了讓用戶激活多線程機制的策略。在Python虛擬機啟動時,多線程機制并沒有被激活,它只支持單線程,一旦用戶調用thread.start_new_thread。
明確指示Python虛擬機創建新的線程,Python就能意識到用戶需要多線程的支持,這個時候,Python虛擬機會自動建立多線程機制需要的數據結構、環境以及那個至關重要的GIL。
在這里,我們終于看到了Python中多線程機制的平臺相關性,在Python25\Python目錄下,有一大批thread_***.h這樣的文件。這些文件中,包裝了不同操作系統的原生線程,并通過統一的接口暴露給Python,比如這里的PyThread_allocate_lock就是這樣一個接口。
我們這里的thread_nt.h中包裝的是Win32平臺的原生thread,在本章中后面的代碼剖析中,還會有大量與平臺相關的代碼,我們都以Win32平臺為例。在PyThread_allocate_lock中,與PyEval_InitThreads非常類似的,它會檢查一個initialized的變量,如果說GIL指示著Python的多線程環境是否已經建立。
那么這個initialized變量就指示著為了使用底層平臺所提供的原生thread,必須的初始化動作是否完成。這些必須的初始化動作通常都是底層操作系統所提供的API,不同的操作系統可能需要不同的初始化動作。
【編輯推薦】