偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

詳細(xì)說明Python虛擬機(jī)狀態(tài)問題

開發(fā) 后端
在Python虛擬機(jī)中提供的thread module接口中,一最不能少的肯定是創(chuàng)建線程的接口,如果沒有這個(gè)接口,那么Python語言還有什么意思?

現(xiàn)在說明一下關(guān)于Python虛擬機(jī)的狀態(tài)問題,實(shí)際上Python當(dāng)前由兩個(gè)原生thread構(gòu)成,一個(gè)是主線程執(zhí)行程序(python.exe)時(shí)操作系統(tǒng)創(chuàng)建的,另一個(gè)是通過thread1.py創(chuàng)建的子線程。

在代碼清單15-1的[1]中,我們注意到boot->interp中保存了Python虛擬機(jī)的PyInter- preterState對象,這個(gè)對象中攜帶了Python的module pool這樣的全局信息,Python中所有的thread都會(huì)共享這些全局信息。

關(guān)于代碼清單15-1的[2]處所示的多線程環(huán)境的初始化動(dòng)作,有一點(diǎn)需要特別說明,當(dāng)Python啟動(dòng)時(shí),是并不支持多線程的。換句話說,Python中支持多線程的數(shù)據(jù)結(jié)構(gòu)以及GIL都是沒有創(chuàng)建的,Python之所以有這種行為是因?yàn)榇蠖鄶?shù)的Python程序都不需要多線程的支持。

  1. [threadmodule.c]  
  2.  
  3. static PyObject* thread_PyThread_start_new_thread(PyObject *self, PyObject  
  4.  
  5.   *fargs)  
  6.  
  7. {  
  8.  
  9.     PyObject *func, *args, *keyw = NULL;  
  10.  
  11.     struct bootstate *boot;  
  12.  
  13.     long ident;  
  14.  
  15.     PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3, &func, &args, &keyw);  
  16.  
  17.     //[1]:創(chuàng)建bootstate結(jié)構(gòu)  
  18.  
  19.     boot = PyMem_NEW(struct bootstate, 1);  
  20.  
  21.     boot->interp = PyThreadState_GET()->interp;  
  22.  
  23.     boot->funcfunc = func;  
  24.  
  25.     boot->argsargs = args;  
  26.  
  27.     boot->keywkeyw = keyw;  
  28.  
  29.     //[2]:初始化多線程環(huán)境  
  30.  
  31.     PyEval_InitThreads(); /* Start the interpreter's thread-awareness */  
  32.  
  33.     //[3]:創(chuàng)建線程  
  34.  
  35.     ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);  
  36.  
  37.     return PyInt_FromLong(ident);  
  38.  
  39. [thread.c]  
  40.  
  41. /* Support for runtime thread stack size tuning.  
  42.  
  43.    A value of 0 means using the platform's default stack size  
  44.  
  45.    or the size specified by the THREAD_STACK_SIZE macro. */  
  46.  
  47. static size_t _pythread_stacksize = 0;  
  48.  
  49. [thread_nt.h]  
  50.  
  51. long PyThread_start_new_thread(void (*func)(void *), void *arg)  
  52.  
  53. {  
  54.  
  55.     unsigned long rv;  
  56.  
  57.     callobj obj;  
  58.  
  59.     obj.id = -1;    /* guilty until proved innocent */  
  60.  
  61.     obj.func = func;  
  62.  
  63.     obj.arg = arg;  
  64.  
  65.     obj.done = CreateSemaphore(NULL, 0, 1, NULL);  
  66.  
  67.     rv = _beginthread(bootstrap, _pythread_stacksize, &obj); /* use default stack size */  
  68.  
  69.     if (rv == (unsigned long)-1) {  
  70.  
  71.         //創(chuàng)建raw thread失敗  
  72.  
  73.         obj.id = -1;  
  74.  
  75.     }  
  76.  
  77.     else {  
  78.  
  79.         WaitForSingleObject(obj.done, INFINITE);  
  80.  
  81.     }  
  82.  
  83.     CloseHandle((HANDLE)obj.done);  
  84.  
  85.     return obj.id;  
  86.  
  87. }  

假如一個(gè)簡單地統(tǒng)計(jì)詞頻的Python腳本中居然出現(xiàn)了多線程,面對這樣的代碼,我們一定都會(huì)抓狂的J。對多線程的支持并非是沒有代價(jià)的,最簡單的一點(diǎn),如果激活多線程機(jī)制。

而執(zhí)行的Python程序中并沒有多線程,那么在100條指令之后,Python虛擬機(jī)同樣會(huì)激活線程的調(diào)度。而如果不激活多線程,Python虛擬機(jī)則不用做這些無用功。所以Python選擇了讓用戶激活多線程機(jī)制的策略。在Python虛擬機(jī)啟動(dòng)時(shí),多線程機(jī)制并沒有被激活,它只支持單線程,一旦用戶調(diào)用thread.start_new_thread。

明確指示Python虛擬機(jī)創(chuàng)建新的線程,Python就能意識到用戶需要多線程的支持,這個(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)的原生線程。#t#

并通過統(tǒng)一的接口暴露給Python,比如這里的PyThread_allocate_lock就是這樣一個(gè)接口。我們這里的thread_nt.h中包裝的是Win32平臺(tái)的原生thread,在本章中后面的代碼剖析中,還會(huì)有大量與平臺(tái)相關(guān)的代碼。

我們都以Win32平臺(tái)為例。一切真相大白了,原來,GIL(NRMUTEX)中的hevent就是Win32平臺(tái)下的Event這個(gè)內(nèi)核對象,而其中的thread_id將記錄任一時(shí)刻獲得GIL的線程的id。

到了這里,Python虛擬機(jī)中的線程互斥機(jī)制的真相漸漸浮出水面,看來Python是通過Win32下的Event來實(shí)現(xiàn)了線程的互斥,熟悉Win32的朋友馬上就可能想到,與這個(gè)Event對應(yīng)的,必定有一個(gè)WaitForSingleObject。

在PyEval_InitThreads通過PyThread_allocate_lock成功地創(chuàng)建了GIL之后,當(dāng)前線程就開始遵循Python的多線程機(jī)制的規(guī)則:在調(diào)用任何Python C API之前,必須首先獲得GIL。因此PyEval_InitThreads緊接著通過PyThread_acquire_lock嘗試獲得GIL。

與InterlockedCompareExchange相同的,InterlockedIncrement也是一個(gè)原子操作,其功能是將mutex->owned的值增加1。從這里可以看到,當(dāng)一個(gè)線程開始等待GIL時(shí),其owned就會(huì)被增加1。顯然我們可以猜測,當(dāng)一個(gè)線程最終釋放GIL時(shí),一定會(huì)將GIL的owned減1,這樣當(dāng)所有需要GIL的線程都最終釋放了GIL之后,owned會(huì)再次變?yōu)?1,意味著GIL再次變?yōu)榭捎谩?/P>

為了清晰地展示這一點(diǎn),我們現(xiàn)在就來看看PyThread_aquire_lock的逆運(yùn)算,PyThread_release_lock每一個(gè)將從運(yùn)行轉(zhuǎn)態(tài)轉(zhuǎn)為等待狀態(tài)的線程都會(huì)在被掛起之前調(diào)用它以釋放對GIL的占有。

【編輯推薦】

  1. 有關(guān)Python系統(tǒng)文件進(jìn)行介紹指導(dǎo)
  2. 如何正確的使用Python函數(shù)
  3. 對Python 構(gòu)建工具進(jìn)行詳細(xì)介紹分析
  4. PythonAndroid淺析Python優(yōu)勢所在
  5. 如何使用Python模塊解析配置文件?
責(zé)任編輯:chenqingxiang 來源: IT168
相關(guān)推薦

2010-02-22 13:20:58

Python中文問題

2009-12-07 13:12:18

WFC端口

2010-02-22 16:26:21

Python編輯

2010-02-22 17:54:07

Python工具

2010-01-19 09:54:19

C++代碼

2009-12-09 15:40:04

Visual Stud

2010-02-22 16:40:22

Python解釋器

2009-12-28 09:26:09

ADO對象

2010-01-13 13:27:00

C++優(yōu)化

2010-02-23 10:14:29

Python 源代碼

2010-02-23 11:18:25

Python 操作符

2010-02-26 09:42:52

Python線程池

2010-02-04 14:41:52

Android菜單類型

2014-09-16 09:57:56

INotifyProp

2010-02-06 17:54:40

Dalvik虛擬機(jī)

2009-12-07 18:06:46

WCF框架

2009-12-08 09:00:14

WCF線程

2010-03-09 10:11:34

Linux掛載命令

2010-07-21 13:17:52

Perl文件讀寫

2010-02-24 15:18:51

Python社區(qū)
點(diǎn)贊
收藏

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