<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                就個人而言,學了這么多年的課程又寫了這么多年的程序,雖然沒有涉及到企業級的項目,但還是體會到了有幾個知識點是非常重要的,包括:面向對象的思想、如何架構一個項目、設計模式來具體解決問題、應用機器學習和深度學習的方法,當然也包括我這篇文章的內容——多線程和并行化處理數據。 這篇文章主要是參考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() ~~~ 代碼的運行結果如下圖所示,它將和后面的并行代碼做對比。 ![](https://box.kancloud.cn/2016-02-23_56cc2eb90fc26.jpg) **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都報錯,估計環境配置問題。 ![](https://box.kancloud.cn/2016-02-23_56cc2eb92379d.jpg) 最后采用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)后應該已經結束了。 ![](https://box.kancloud.cn/2016-02-23_56cc2eb933d94.jpg) 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是分行顯示了。 ![](https://box.kancloud.cn/2016-02-23_56cc2eb945ba1.jpg) 所有的線程都創建之后,再一起調用**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() ~~~ 運行結果如下圖所示,傳遞的是一個可調用的類,而不是一個函數。 ![](https://box.kancloud.cn/2016-02-23_56cc2eb956255.jpg) 創建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() ~~~ 運行結果如下圖所示: ![](https://box.kancloud.cn/2016-02-23_56cc2eb96a310.jpg) **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。 ![](https://box.kancloud.cn/2016-02-23_56cc2eb97dab8.jpg) 至于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/))??
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看