就個人而言,學了這么多年的課程又寫了這么多年的程序,雖然沒有涉及到企業級的項目,但還是體會到了有幾個知識點是非常重要的,包括:面向對象的思想、如何架構一個項目、設計模式來具體解決問題、應用機器學習和深度學習的方法,當然也包括我這篇文章的內容——多線程和并行化處理數據。
這篇文章主要是參考Wesley J. Chun的《Python核心編程(第二版)》書籍多線程部分,并結合我以前的一些實例進行簡單分析。尤其是在大數據、Hadoop\Spark、分布式開發流行的今天,這些基礎同樣很重要。希望對你有所幫助吧!
PS:推薦大家閱讀《Python核心編程》和《Python基礎教程》兩本書~
強推:[http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html](http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html)
##一. 線程和進程的概念
**1.為什么引入多線程編程?**
在多線程(Multithreaded,MT)編程出現之前,電腦程序的運行由一個執行序列組成,執行序列按順序在主機的中央處理器CPU中運行。即使整個程序由多個相互獨立無關的子任務組成,程序都會順序執行。
由于并行處理可以大幅度地提升整個任務的效率,故引入多線程編程。
多線程中任務具有以下特點:
(1) 這些任務的本質是異步的,需要有多個并發事務;
(2) 各個事務的運行順序可以是不確定的、隨機的、不可預測的。
這樣的編程任務可以分成多個執行流,每個流都有一個要完成的目標。再根據不同的應用,這些子任務可能都要計算出一個中間結果,用于合并得到最后的結果。
**2.什么是進程?**
計算機程序只不過是磁盤中可執行的二進制(或其他類型)的數據。它們只有在被讀取到內存中,被操作系統調用時才開始它們的生命周期。
進程(亦稱為重量級進程)是程序的一次執行。每個進程都有自己的地址空間、內存、數據棧及其他記錄其運行軌跡的輔助數據。操作系統管理在其上運行所有的進程,并為這些進程公平分配時間、進程也可以通過[fork](http://www.cnblogs.com/bastard/archive/2012/08/31/2664896.html)和spawn操作來完成其他的任務。
不過進程有自己的內存空間,數據棧等,所以只能使用進程間通訊(interprocess communication, IPC),而不能直接共享信息。
**3.什么是線程?**
線程(亦稱為輕量級進程)跟進程有些相似,不同的是:所有的線程運行在同一個進程中,共享相同的運行環境。它們可以被想象成是在主進程或“主線程”中并行運行的“迷你進程”。
線程有開始,順序執行和結束三部分。它有一個自己的指令指針,記錄自己運行到什么地方。線程的運行可能被搶占(中斷)或暫時的被掛起(睡眠),讓其他線程運行,這叫做讓步。
一個進程中的各個線程之間共享同一片數據空間,所以線程之間可以比進程之間更方便地共享數據以及相互通訊。線程一般都是并發執行的,正是由于這種并行和數據共享的機制使得多個任務的合作變成可能。
實際上,在單CPU的系統中,真正的并發是不可能的,每個線程會被安排成每次只運行一小會,然后就把CPU讓出來,讓其他的線程去運行。在進程的整個運行過程中,每個線程都只做自己的事,在需要的時候跟其他的線程共享運行的結果。
當然,這樣的共享并不是完全沒有危險的。如果多個線程共同訪問同一片數據,則由于數據訪問的順序不同,有可能導致數據結果的不一致的問題,即競態條件(race condition)。同樣,大多數線程庫都帶有一些列的同步原語,來控制線程的執行和數據的訪問。
另一個需要注意的是由于有的函數會在完成之前阻塞住,在沒有特別為多線程做修改的情況下,這種“貪婪”的函數會讓CPU的時間分配有所傾斜,導致各個線程分配到的運行時間可能不盡相同,不盡公平。
**4.簡述進程和線程的區別**
參考下面三篇文章:
[進程和線程關系及區別 -?yaosiming2011](http://blog.csdn.net/yaosiming2011/article/details/44280797)
[進程與線程的區別 -?flashsky](http://www.cnblogs.com/flashsky/articles/642720.html)
[應屆生經典面試題:說說進程與線程的區別與聯系 -?way_testlife](http://www.cnblogs.com/way_testlife/archive/2011/04/16/2018312.html)
##二. Python線程和全局解釋器鎖
**1.全局解釋器鎖(GIL)**
Python代碼的執行由Python虛擬機(也叫解釋器主循環)來控制。Python在設置之初就考慮到要在主循環中,同時只有一個線程在執行,就像單CPU的系統中運行多個進程那樣,內存中可以存放多個程序,但任意時刻,只有一個程序在CPU中運行。同樣,雖然Python解釋器可以“運行”多個線程,但任意時刻,只有一個線程在解釋器中運行。
對Python虛擬機的訪問由全局解釋器鎖(global interpreter lock,GIL)來控制,正是這個鎖能保證同一時刻只有一個線程在運行。在多線程環境中,Python虛擬機按一下方式執行:
(1) 設置GIL
(2) 切換到一個線程去運行
(3) 運行:
a. 指定數量的字節碼的指令,或者
b. 線程主動讓出控制(可以調用time.sleep(0))
(4) 把線程設置為睡眠狀態
(5) 解鎖GIL
(6) 再次重復以上所有步驟
在調用外部代碼(如C/C++擴展函數)的時候,GIL將會被鎖定,直到這個函數結束為止(由于這期間沒有Python的字節碼被運行,所以不會做線程切換)。編寫擴展的程序員可以主動解鎖GIL。不過Python開發人員則不用擔心在這些情況下你的Python代碼會被鎖住。
對源代碼,解釋器主循環和GIL感興趣的人,可以看看Python/ceval.c文件。
**2.退出線程**
當一個線程結束計算,它就退出了。線程可以調用thread.exit()之類的退出函數,也可以使用Python退出進程的標準方法,如sys.exit()或拋出一個SystemExit異常等。不過,你不可以直接殺掉Kill一個線程。
后面會講述兩個與線程相關的模塊,在這兩個模塊中,該書中不建議使用thread模塊。主要原因是當主線程退出的時候,其他所有線程沒有被清除就退出了。而threading模塊就能確保所有“重要的”子線程都退出后,進程才會結束。
主線程應該是一個好的管理者,它要了解每個線程都要做些什么事,線程都需要什么數據和什么參數,以及在線程結束的時候,它們都提供了什么結果。這樣,主線程就可以把各個線程的結果組成一個有意義的最后結果。
在Python2.7交互式解釋器中導入**import thread**沒有報錯即表示線程可用。
**3.沒有線程的例子**
使用time.sleep()函數來演示線程的工作,這個例子主要為后面線程做對比。time.sleep()需要一個浮點型的參數,來指定“睡眠”的時間(單位秒)。這就相當于程序的運行會被掛起指定的時間。
代碼解釋:兩個計時器,loop0睡眠4秒,loop1()睡眠2秒,它們是在一個進程或者線程中,順序地執行loop0()和loop1(),那總運行時間為6秒。有可能啟動過程中會再花些時間。
~~~
from time import sleep, ctime
def loop0():
print 'Start loop 0 at:', ctime()
sleep(4)
print 'Loop 0 done at:', ctime()
def loop1():
print 'Start loop 1 at:', ctime()
sleep(2)
print 'Loop 1 done at:', ctime()
def main():
print 'Starting at:', ctime()
loop0()
loop1()
print 'All done at:', ctime()
if __name__ == '__main__':
main()
~~~
代碼的運行結果如下圖所示,它將和后面的并行代碼做對比。

**4.避免使用thread模塊**
Python提供了幾個用于多線程編程的模塊,包括thread、threading和Queue等。
(1) thread模塊: 允許程序員創建和管理線程,它提供了基本的線程和鎖的支持。
(2) threading模塊: 允許程序員創建和管理線程,它提供了更高級別,更強的線程管理的功能。
(3) Queue模塊: 允許用戶創建一個可用于多個線程間共享數據的隊列數據結構。
下面簡單分析為什么需要避免使用thread模塊?
(1) 首先更高級別的threading模塊更為先進,對線程的支持更為完善,而且使用thread模塊里的屬性有可能會與threading出現沖突。
(2) 其次,低級別的thread模塊的同步原語很少(實際只有一個),而threading模塊則有很多。
(3) 另一個原因是thread對你的進程什么時候應該結束完全沒有控制,當主線程結束時,所有的線程都會被強制結束掉,沒有警告也不會有正常的清除工作。而threading模塊能確保重要的子線程退出后進程才退出。
當然,為了你更好的理解線程,還是會對thread進行講解。但是我們只建議那些有經驗的專家想訪問線程的底層結構時,才使用thread模塊。而如果可以,你的第一個線程程序應盡可能使用threading等高級別的模塊。
?
##三. thread模塊
**1.基礎知識**
首先來看看thread模塊都提供了些什么。除了產生線程外,thread模塊也提供了基本的同步數據結構鎖對象(lock object,也叫原語鎖、簡單鎖、互斥鎖、互斥量、二值信號量)。同步原語與線程的管理是密不可分的。
常用的線程模塊函數
<table class=" " cellpadding="0" cellspacing="0" style="line-height:26px; padding:0px; margin:0px auto 10px; font-size:12px; border-collapse:collapse; color:rgb(85,85,85); font-family:宋體,'Arial Narrow',arial,serif"><tbody style="padding:0px; margin:0px"><tr style="padding:0px; margin:0px"><td valign="top" width="300" style="border:1px solid rgb(0,0,0); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">模塊函數</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid solid solid none; border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="padding:0px; margin:0px"><span style="font-family:宋體; padding:0px; margin:0px"><span style="color:rgb(0,0,0)">描述</span></span></span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:none solid solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">start_new_thread(function, args kwargs=None)</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:none solid solid none; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">產生一個新線程,在新線程中用指定的參數和可選的kwargs來調用該函數</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:none solid solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">allocate_lock()</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:none solid solid none; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">分配一個LockType類型的鎖對象</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:none solid solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">exit()</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:none solid solid none; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">讓線程退出</span></p></td></tr></tbody></table>
LockType類型鎖對象方
<table class=" " cellpadding="0" cellspacing="0" style="line-height:26px; padding:0px; margin:0px auto 10px; font-size:12px; border-collapse:collapse; color:rgb(85,85,85); font-family:宋體,'Arial Narrow',arial,serif"><tbody style="padding:0px; margin:0px"><tr style="padding:0px; margin:0px"><td valign="top" width="300" style="border:1px solid rgb(0,0,0); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="padding:0px; margin:0px"><span style="color:rgb(0,0,0)"><span style="font-family:宋體; padding:0px; margin:0px">類型鎖對象方法</span></span></span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid solid solid none; border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="padding:0px; margin:0px"><span style="font-family:宋體; padding:0px; margin:0px"><span style="color:rgb(0,0,0)">描述</span></span></span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:none solid solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">acquire(wait=None)</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:none solid solid none; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">嘗試獲取鎖對象</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:none solid solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">locked()</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:none solid solid none; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">如果獲取了鎖對象返回True,否則返回False</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:none solid solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">release()</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:none solid solid none; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">釋放鎖</span></p></td></tr></tbody></table>
start_new_thread()函數是thread模塊的一個關鍵函數,它的語法和內建的apply()函數一樣,其參數為:函數,函數的參數以及可選的關鍵字的參數。不同的是,函數不是在主線程里運行,而是產生一個新的線程來運行這個函數。
**2.Thread模塊實現代碼**
現在實現一個線程的代碼,與前面沒有線程總運行時間為6秒的進行對比。
~~~
import thread
from time import sleep, ctime
def loop0():
print 'Start loop 0 at:', ctime()
sleep(4)
print 'Loop 0 done at:', ctime()
def loop1():
print 'Start loop 1 at:', ctime()
sleep(2)
print 'Loop 1 done at:', ctime()
def main():
try:
print 'Starting at:', ctime()
thread.start_new_thread(loop0, ())
thread.start_new_thread(loop1, ())
sleep(6)
print 'All done at:', ctime()
except Exception,e:
print 'Error:',e
finally:
print 'END\n'
if __name__ == '__main__':
main()
~~~
代碼解釋:
使用thread模塊提供簡單的額多線程機制。loop0和loop1并發地被執行(顯然,短的那個先結束),總的運行時間為最慢的那個線程的運行時間,而不是所有的線程的運行時間之和。start_new_thread()要求一定要有前兩個參數,即使運行的函數不要參數,也要傳一個空的元組。
由于采用Python IDLE運行總是報錯Runtime,而且已經設置了sleep(6)。運行一個線程勉強能運行,兩個線程無論是thread或threading都報錯,估計環境配置問題。

最后采用Cygwin Terminal模擬Linux下運行程序。可以發現loop1和loop0是并發執行的,其中loop1先結束運行2秒,而loop0運行4秒。
同時程序主函數中多了個sleep(6),為什么要加這一句話呢?
因為如果我們沒有讓主線程停下來,那主線程就會運行下一條語句,顯示“All done”,然后就關閉運行著loop0和loop1的兩個線程,退出了。
我們沒有寫讓主線程停下來等所有子線程結束后再繼續運行的代碼,這就是前面所說的需要同步的原因。在這里,我們使用sleep(6)作為同步機制。設置6秒,兩個線程一個4秒(53-57),一個2秒(53-55),在主線程等待6秒(53-59)后應該已經結束了。

cygwin需要用到的常見用法包括,也可以安裝VIM編輯器:
? ? ? ? ? ? ? ? ?cd c: ? ? ?進入 'c:' 目錄,空格用'\ '轉義字符
? ? ? ? ? ? ? ? ?pwd ? ? ? ? 顯示工作路徑
? ? ? ? ? ? ? ? ? ?ls ? ? ? ? 查看目錄中的文件
? ? ? ? ? ? ? ? ?file test.py ? ? ? ? ? ? ? ? 查看文件內容
? ? ? ? ? ? ? ? ?python test.py ? ? ? ? ?運行python程序
配置方法見:[http://blog.sina.com.cn/s/blog_691ebcfc0101lgme.html](http://blog.sina.com.cn/s/blog_691ebcfc0101lgme.html)
下載地址見:[http://pan.baidu.com/s/1jGYEtro](http://pan.baidu.com/s/1jGYEtro)
**3.線程加鎖方法**
那么,有什么好的管理線程的方法呢?而不是在主線程里做個額外的延時6秒操作。因為總的運行時間并不比單線程的代碼少;而且使用sleep()函數做線程的同步操作是不可靠的;如果循環的執行時間不能事先確定的話,這可能會造成主線程過早或過晚的退出。
這就需要引入鎖的概念。下面代碼執行loop函數,與前面代碼的區別是不用為線程什么時候結束再做額外的等待了。使用鎖之后,可以在兩個線程都退出后,馬上退出。
~~~
#coding=utf-8
import thread
from time import sleep, ctime
loops = [4,2] #等待時間
#鎖序號 等待時間 鎖對象
def loop(nloop, nsec, lock):
print 'start loop', nloop, 'at:', ctime()
sleep(nsec)
print 'loop', nloop, 'done at:', ctime()
lock.release() #解鎖
def main():
print 'starting at:', ctime()
locks =[]
nloops = range(len(loops)) #以loops數組創建列表并賦值給nloops
for i in nloops:
lock = thread.allocate_lock() #創建鎖對象
lock.acquire() #獲取鎖對象 加鎖
locks.append(lock) #追加到locks[]數組中
#執行多線程 (函數名,函數參數)
for i in nloops:
thread.start_new_thread(loop,(i,loops[i],locks[i]))
#循環等待順序檢查每個所都被解鎖才停止
for i in nloops:
while locks[i].locked():
pass
print 'all end:', ctime()
if __name__ == '__main__':
main()
~~~
運行結果如下:
Starting at: Tue Dec ?8 21:57:56 2015
Start loop 0?at:?Tue Dec ?8 21:57:56 2015
Start loop 1 at: Tue Dec ?8 21:57:56 2015
Loop 1 done at: Tue Dec ?8 21:57:58 2015
Loop 0 done at: Tue Dec ?8 21:58:00 2015
All end: Tue Dec ?8 21:58:00 2015
我們在函數中記錄下循環的號碼和睡眠的時間,同時每個線程都會被分配一個事先已經獲得的鎖,在sleep()的時間到了之后就釋放相應的鎖以通知住線程,這個線程已經結束了。
(1) loops[4, 2]定義睡眠時間 nloops=range(len(loops))創建列表[0, 1] 號碼;
(2) 調用thread.allocate_lock()函數創建一個鎖的列表,并分別調用各個鎖的acquire()函數獲得鎖對象。獲得鎖表示“把鎖鎖上”,并放到鎖列表locks中;
(3) 再循環創建線程,調用thread.start_new_thread(loop,(i,loops[i],locks[i]))。參數對應線程循環號、睡眠時間和鎖。
(4) 在線程結束時,需要做解鎖操作,調用lock.release()函數;
(5) 最后一個循環是坐在那一直等待(達到暫停主線程的目的),直到兩個鎖都被解鎖才繼續運行。它是順序檢查每個鎖,主線程需不停地對所有鎖進行檢查直到都釋放。
為什么我們不在創建鎖的循環里創建線程呢?一方面是想實現線程的同步,所以要讓“所有的馬同時沖出柵欄”;另外獲取鎖要花些時間,如果線程退出太快,可能導致還沒有獲得鎖,線程就已經結束了。
最后再強調下,thread模塊僅僅了解就行,你應該使用更高級別的threading等。
##四. threading模塊
threading模塊不僅提供了Thread類,還提供了各種非常好用的同步機制。如下表列出了threading模塊里所有的對象。
<table class=" " cellpadding="0" cellspacing="0" style="line-height:26px; padding:0px; margin:0px auto 10px; font-size:12px; border-collapse:collapse; color:rgb(85,85,85); font-family:宋體,'Arial Narrow',arial,serif"><tbody style="padding:0px; margin:0px"><tr style="padding:0px; margin:0px"><td valign="top" width="250" style="border:1px solid; border-color:rgb(0,0,0); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">threading模塊對象</span></p></td><td valign="top" width="520" style="border:1px solid; border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="padding:0px; margin:0px"><span style="font-family:宋體; padding:0px; margin:0px"><span style="color:rgb(0,0,0)">描述</span></span></span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">Thread</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">表示一個線程的執行的對象</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">Lock</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:rgb(0,0,0)">鎖原語對象(跟thread模塊里的鎖對象相同)</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">RLock</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">可重入鎖對象。使單線程可以再次獲得已經獲得了的鎖(遞歸鎖定)</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">Condition</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">條件變量對象能讓一個線程停下來,等待其他線程滿足了某個“條件”。如狀態的改變或值的改變</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">Event</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">通用的條件變量。多個線程可以等待某個時間的發生,在事件發生后,所有的線程都被激活</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">Semaphore</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">為等待鎖的線程提供一個類似“等候室”的結構</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">BoundedSemaphore</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">與Semaphore類似,只是它不允許超過初始值</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">Timer</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">與thread類似,只是它要等待一段時間后才開始運行</span></p></td></tr></tbody></table>
**1.守護線程**
其中thread模塊需要避免的一個原因是:它不支持守護線程。當主線程退出時,所有的子線程不論它們是否還在工作,都會被強行退出。有時我們并不期望這種行為,這就引入了守護線程的概念。
Threading模塊支持守護線程,它們工作流程如下:守護線程一般是一個等待客戶請求的服務器,如果沒有客戶提出請求,它就在那等著。如果你設定一個線程為守護線程,就表示你在說這個線程是不重要的,在進程退出時,不用等待這個線程退出,正如網絡編程中服務器線程運行在一個無限循環中,一般不會退出的。
如果你的主線程要退出的時候,不用等待那些子線程完成,那就設定這些線程的**daemon屬性**。即,線程開始(調用thread.start())之前,調用**setDaemon()函數**設定線程的daemon標準(thread.setDaemon(True))就表示這個線程“不重要”。
如果你想要等待子線程完成再退出,那就什么都不用做,或者顯示地調用**thread.setDaemon(False)**以保證其daemon標志位False。你可以調用thread.isDaemon()函數來判斷其daemon標志的值。
新的子線程會繼承其父線程的daemon標志,整個Python會在所有的非守護線程退出后才會結束,即進程中沒有非守護線程存在的時候才結束。
**2.Thread類**
threading的Thread類是你主要的運行對象。它有很多thread模塊里沒有的函數。
<table class=" " cellpadding="0" cellspacing="0" style="line-height:26px; padding:0px; margin:0px auto 10px; font-size:12px; border-collapse:collapse; color:rgb(85,85,85); font-family:宋體,'Arial Narrow',arial,serif"><tbody style="padding:0px; margin:0px"><tr style="padding:0px; margin:0px"><td valign="top" width="250" style="border:1px solid; border-color:rgb(0,0,0); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">函數</span></p></td><td valign="top" width="520" style="border:1px solid; border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="padding:0px; margin:0px"><span style="font-family:宋體; padding:0px; margin:0px"><span style="color:rgb(0,0,0)">描述</span></span></span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">start()</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">開始線程的執行</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">run()</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">定義線程的功能的函數(一般會被子類重寫)</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">join(timeout=None)</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">程序掛起,直到線程結束;如果給了timeout,則最多阻塞timeout秒</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">getName()</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">返回線程的名字</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">setName(name)</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">設置線程的名字</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">isAlive()</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">布爾標志,表示這個線程是否還在運行中</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">isDaemon()</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">返回線程的daemon標志</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">setDaemon(daemonic)</span></p></td><td valign="top" width="482" style="border:1px solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">把線程的daemon標志設為daemonic(一定要在調用start()函數前調用)</span></p></td></tr></tbody></table>
? ? ? 用Thread類,可以用多種方法來創建線程。現在介紹三種方法,你可以選擇自己喜歡或社和自己程序的方法(通常選擇最后一個):
? ? ? (1) 創建一個Thread的實例,傳給它一個函數;
? ? ? (2) 創建一個Thread的實例,傳給它一個可調用的類對象;
? ? ? (3) 從Thread派生出一個子類,創建一個這個子類的實例。
**3.創建Thread實例,傳給它一個函數**
這第一個例子使用方法一,把函數及其參數如上面Thread模塊的例子一樣傳進去。主要變化包括:添加了一些Thread對象;在實例化每個Thread對象時,把函數(target)和參數(args)都傳進去,得到返回的Thread實例。
實例化一個Thread調用Thread()方法與調用thread.start_new_thread()之間的最大區別是:新的線程不會立即開始。在你創建線程對象,但不想馬上開始運行線程的時候,這是一個很有用的同步特性。
threading模塊的Thread類有一個join()函數,允許主線程等待線程的結束。
~~~
#coding=utf-8
import threading
from time import sleep, ctime
loops = [4,2] #睡眠時間
def loop(nloop, nsec):
print 'Start loop', nloop, 'at:', ctime()
sleep(nsec)
print 'Loop', nloop, 'done at:', ctime()
def main():
print 'Starting at:', ctime()
threads = []
nloops = range(len(loops)) #列表[0,1]
#創建線程
for i in nloops:
t = threading.Thread(target=loop,args=(i,loops[i]))
threads.append(t)
#開始線程
for i in nloops:
threads[i].start()
#等待所有結束線程
for i in nloops:
threads[i].join()
print 'All end:', ctime()
if __name__ == '__main__':
main()
~~~
運行結果如下圖所示:其中loop0和loop1并行執行,loop1先結束共執行2秒,loop0后結束執行4秒,總共運行時間4秒。注意:此時Start是分行顯示了。

所有的線程都創建之后,再一起調用**start()函數啟動線程**,而不是創建一個啟動一個。而且,不用再管理一堆鎖(分配鎖、獲得鎖、釋放鎖、檢查鎖的狀態等),只要簡單地對每個線程調用**join()函數**就可以了。
join()會**等到線程結束**,或者在給了timeout參數的時候,等到超時為止。使用join()比使用一個等待鎖釋放的無限循環清楚一些(也稱“自旋鎖”)。
join()的另一個比較重要的方法是它可以**完全不用調用**。一旦線程啟動后,就會一直運行,直到線程的函數結束,退出為止。
如果你的主線程除了等線程結束外,還有其他的事情要做(如處理或等待其他的客戶請求),那就不用調用join(),只有在你要等待線程結束的時候才要調用join()。
**4.創建一個Thread實例,傳給它一個可調用的類對象**
這是第二個方法,與傳一個函數很相似,但它是傳一個可調用的類的實例供線程啟動的時候執行,這是多線程編程的一個更為面向對象的方法。相對于一個或幾個函數來說,由于類對象里可以使用類請打的功能,可以保存更多的信息,這種方法更為靈活。
~~~
#coding=utf-8
import threading
from time import sleep, ctime
loops = [4,2] #睡眠時間
class ThreadFunc(object):
def __init__(self, func, args, name=''):
self.name=name
self.func=func
self.args=args
def __call__(self):
apply(self.func, self.args)
def loop(nloop, nsec):
print "Start loop", nloop, 'at:', ctime()
sleep(nsec)
print 'Loop', nloop, 'done at:', ctime()
def main():
print 'Starting at:', ctime()
threads=[]
nloops = range(len(loops)) #列表[0,1]
for i in nloops:
#調用ThreadFunc類實例化的對象,創建所有線程
t = threading.Thread(
target=ThreadFunc(loop, (i,loops[i]), loop.__name__)
)
threads.append(t)
#開始線程
for i in nloops:
threads[i].start()
#等待所有結束線程
for i in nloops:
threads[i].join()
print 'All end:', ctime()
if __name__ == '__main__':
main()
~~~
運行結果如下圖所示,傳遞的是一個可調用的類,而不是一個函數。

創建Thread對象時會實例化一個可調用類ThreadFunc的類對象。這個類保存了函數的參數,函數本身以及函數的名字字符串。
構造器__init__()函數:初始化賦值工作;
特殊函數__call__():由于我們已經有要用的參數,所以就不用再傳到Thread()構造器中;由于我們有一個參數的元組,這時要在代碼中使用apply()函數。
apply(func?[,?args?[,?kwargs?]])?函數:用于當函數參數已經存在于一個元組或字典中時,間接地調用函數。args是一個包含將要提供給函數的按位置傳遞的參數的元組。如果省略了args,任何參數都不會被傳遞,kwargs是一個包含關鍵字參數的字典。
~~~
def say(a, b):
print a, b
apply(say,("Eastmount", "Python線程"))
# 輸出
# Eastmount Python線程
~~~
**5.Thread派生一個子類,創建這個子類的實例**
這是第三個方法,主要是如何子類化Thread類,該方法與第二個方法類似。其中創建子類方法和調用類對象方法的最重要改變是:
(1) MyThread子類的構造器一定要先調用基類的構造器;
(2) 之前特殊函數__call__()在子類中,名字要改為run()。
~~~
#coding=utf-8
import threading
from time import sleep, ctime
loops = [4,2] #睡眠時間
class MyThread(threading.Thread):
def __init__(self, func, args, name=''):
threading.Thread.__init__(self)
self.name=name
self.func=func
self.args=args
def run(self): #run()函數
apply(self.func, self.args)
def loop(nloop, nsec):
print "Start loop", nloop, 'at:', ctime()
sleep(nsec)
print 'Loop', nloop, 'done at:', ctime()
def main():
print 'Starting at:', ctime()
threads=[]
nloops = range(len(loops)) #列表[0,1]
for i in nloops:
#子類MyThread實例化,創建所有線程
t = MyThread(loop, (i,loops[i]), loop.__name__)
threads.append(t)
#開始線程
for i in nloops:
threads[i].start()
#等待所有結束線程
for i in nloops:
threads[i].join()
print 'All end:', ctime()
if __name__ == '__main__':
main()
~~~
運行結果如下圖所示:

**6.線程運行斐波那契、階乘和加和**
需要在MyThread類中加入輸出信息,除了使用apply()函數運行斐波那契、接觸和加和函數外,還把結果保存到實現的self.res屬性中,并創建一個函數getResult()得到結果。換句話說,子類方法更加靈活。
~~~
#coding=utf-8
import threading
from time import sleep, ctime
class MyThread(threading.Thread):
def __init__(self, func, args, name=''):
threading.Thread.__init__(self)
self.name=name
self.func=func
self.args=args
def getResult(self):
return self.res
def run(self): #run()函數
print "Starting", self.name, 'at:', ctime()
self.res = apply(self.func, self.args)
print self.name, 'finished at:', ctime()
~~~
? ? ? 在threadfunc.py文件中調用前面定義的Thread子類,myThread.py中的MyThread類。由于這些函數運行得很快(斐波那契函數運行慢些),使用sleep()函數比較它們的時間。實際工作中不需要添加sleep()函數。
~~~
#coding=utf-8
from myThread import MyThread #myThread.py文件中MyThread類
from time import sleep, ctime
#斐波那契函數
def fib(x):
sleep(0.005)
if x < 2:
return 1
return (fib(x-2) + fib(x-1))
#階乘函數 factorial calculation
def fac(x):
sleep(0.1)
if x < 2:
return 1
return (x * fac(x-1))
#求和函數
def sum(x):
sleep(0.1)
if x < 2:
return 1
return (x + sum(x-1))
funcs = [fib, fac, sum]
n = 14
def main():
nfuncs = range(len(funcs))
print '***單線程方法***'
for i in nfuncs:
print 'Starting', funcs[i].__name__, 'at:', ctime()
print funcs[i](n)
print 'Finished', funcs[i].__name__, 'at:', ctime()
print '***結束單線程***'
print ' '
print '***多線程方法***'
threads = []
for i in nfuncs:
#調用MyThread類實例化的對象,創建所有線程
t = MyThread(funcs[i], (n,), funcs[i].__name__)
threads.append(t)
#開始線程
for i in nfuncs:
threads[i].start()
#等待所有結束線程
for i in nfuncs:
threads[i].join()
print threads[i].getResult()
print '***結束多線程***'
if __name__ == '__main__':
main()
~~~
運行結果如下圖所示,單線程運行10s,多線程運行6s。

至于Queue模塊這里就不再敘述了。
下面介紹除了各種同步對象和線程對象外,threading模塊還提供了一些函數。
<table class=" " cellpadding="0" cellspacing="0" style="line-height:26px; padding:0px; margin:0px auto 10px; font-size:12px; border-collapse:collapse; color:rgb(85,85,85); font-family:宋體,'Arial Narrow',arial,serif"><tbody style="padding:0px; margin:0px"><tr style="padding:0px; margin:0px"><td valign="top" width="250" style="border:1px solid rgb(0,0,0); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">函數</span></p></td><td valign="top" width="520" style="border-width:1px; border-style:solid; border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="padding:0px; margin:0px"><span style="font-family:宋體; padding:0px; margin:0px"><span style="color:rgb(0,0,0)">描述</span></span></span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">activeCount()</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">當前活動的線程對象的數量</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">currentThread()</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">返回當前線程對象</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">enumerate()</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">返回當前活動線程的列表</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">settrace(func)</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">為所有線程設置一個跟蹤函數</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">setprofile(func)</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">為所有線程設置一個profile函數</span></p></td></tr></tbody></table>
最后給出一些多線程編程中可能用得到的模塊。
<table class=" " cellpadding="0" cellspacing="0" style="line-height:26px; padding:0px; margin:0px auto 10px; font-size:12px; border-collapse:collapse; color:rgb(85,85,85); font-family:宋體,'Arial Narrow',arial,serif"><tbody style="padding:0px; margin:0px"><tr style="padding:0px; margin:0px"><td valign="top" width="250" style="border:1px solid rgb(0,0,0); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">模塊</span></p></td><td valign="top" width="520" style="border-width:1px; border-style:solid; border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px; background-color:rgb(242,242,242)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="padding:0px; margin:0px"><span style="font-family:宋體; padding:0px; margin:0px"><span style="color:rgb(0,0,0)">描述</span></span></span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:rgb(0,0,0)">thread</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">基本的、低級別的線程模塊</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">threading</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:rgb(0,0,0)">高級別的線程和同步對象</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">Queue</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">供多線程使用的同步先進先出(FIFO)隊列</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">mutex</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:#000000">互斥對象</span></p></td></tr><tr style="padding:0px; margin:0px"><td valign="top" width="226" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="color:#000000">SocketServer</span></p></td><td valign="top" width="482" style="border-width:1px; border-style:solid; border-color:rgb(221,221,221) rgb(0,0,0) rgb(0,0,0) rgb(221,221,221); padding:0px 7px; margin:0px"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; clear:both; height:auto; overflow:hidden"><span style="font-family:宋體; color:rgb(0,0,0)">具有線程控制的TCP和UDP管理器<br/></span></p></td></tr></tbody></table>
總之,這篇文章主要是參考《Python核心編程》的,希望文章對你有所幫助~尤其是初學Python編程的,同時為后面我學習多線程的爬蟲或分布式爬蟲做鋪墊。這篇文章花了自己一些時間,寫到半夜;寫文不易,且看且珍惜吧!勿噴~
(By:Eastmount 2015-12-09 半夜5點 ?[http://blog.csdn.net/eastmount/](http://blog.csdn.net/eastmount/))??
- 前言
- [Python學習] 專題一.函數的基礎知識
- [Python學習] 專題二.條件語句和循環語句的基礎知識
- [Python學習] 專題三.字符串的基礎知識
- [Python學習] 簡單網絡爬蟲抓取博客文章及思想介紹
- [Python學習] 專題四.文件基礎知識
- [python學習] 簡單爬取維基百科程序語言消息盒
- [python學習] 簡單爬取圖片網站圖庫中圖片
- [python知識] 爬蟲知識之BeautifulSoup庫安裝及簡單介紹
- [python+nltk] 自然語言處理簡單介紹和NLTK壞境配置及入門知識(一)
- [python學習] 模仿瀏覽器下載CSDN源文并實現PDF格式備份
- [Python學習] 簡單爬取CSDN下載資源信息
- [Python] 專題五.列表基礎知識 二維list排序、獲取下標和處理txt文本實例
- [Python學習] 專題六.局部變量、全局變量global、導入模塊變量
- [python] 專題七.網絡編程之套接字Socket、TCP和UDP通信實例
- [python] 專題八.多線程編程之thread和threading