qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          python多線程thread

          在使用多線程之前,我們首頁要理解什么是進程和線程。

          什么是進程?

          計算機程序只不過是磁盤中可執行的,二進制(或其它類型)的數據。它們只有在被讀取到內存中,被操作系統調用的時候才開始它們的生命期。進程(有時被稱為重量級進程)是程序的一次執行。每個進程都有自己的地址空間,內存,數據棧以及其它記錄其運行軌跡的輔助數據。操作系統管理在其上運行的所有進程,并為這些進程公平地分配時間。

          什么是線程?

          線程(有時被稱為輕量級進程)跟進程有些相似,不同的是,所有的線程運行在同一個進程中,共享相同的運行環境。我們可以想像成是在主進程或“主線程”中并行運行的“迷你進程”。

           

           7.2.1、單線程

            在單線程中順序執行兩個循環。一定要一個循環結束后,另一個才能開始。總時間是各個循環運行時間之和。 

          onetherad.py

          復制代碼
          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 'start:', ctime()     loop0()      loop1()     print 'all end:', ctime()       if __name__ == '__main__':     main()
          復制代碼

          運行結果:

          start loop 0 at: Mon Dec 23 09:59:44 2013 loop 0 done at: Mon Dec 23 09:59:48 2013 start loop 1 at: Mon Dec 23 09:59:48 2013 loop 1 done at: Mon Dec 23 09:59:50 2013 all end: Mon Dec 23 09:59:50 2013

            Python通過兩個標準庫threadthreading提供對線程的支持。thread提供了低級別的、原始的線程以及一個簡單的鎖。threading基于Java的線程模型設計。鎖(Lock)和條件變量(Condition)在Java中是對象的基本行為(每一個對象都自帶了鎖和條件變量),而在Python中則是獨立的對象。

           

           

           7.2.1、thread模塊

           

          mtsleep1.py

          復制代碼
          import thread  from time import sleep, ctime  loops = [4,2] 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 'start:', ctime()      thread.start_new_thread(loop0, ())      thread.start_new_thread(loop1, ())      sleep(6)     print 'all end:', ctime()   if __name__ == '__main__':     main() 
          復制代碼

            start_new_thread()要求一定要有前兩個參數。所以,就算我們想要運行的函數不要參數,我們也要傳一個空的元組。 

            這個程序的輸出與之前的輸出大不相同,之前是運行了 6秒,而現在則是 秒,是最長的循環的運行時間與其它的代碼的時間總和。

          運行結果:

          start: Mon Dec 23 10:05:09 2013 start loop 0 at: Mon Dec 23 10:05:09 2013 start loop 1 at: Mon Dec 23 10:05:09 2013 loop 1 done at: Mon Dec 23 10:05:11 2013 loop 0 done at: Mon Dec 23 10:05:13 2013 all end: Mon Dec 23 10:05:15 2013

             睡眠 秒和 秒的代碼現在是并發執行的。這樣,就使得總的運行時間被縮短了。你可以看到,loop1 甚至在 loop0 前面就結束了。

            程序的一大不同之處就是多了一個“sleep(6)”的函數調用。如果我們沒有讓主線程停下來,那主線程就會運行下一條語句,顯示“all end”,然后就關閉運行著 loop0()和 loop1()的兩個線程并退出了。我們使用 秒是因為我們已經知道,兩個線程(你知道,一個要 秒,一個要 秒)在主線程等待 秒后應該已經結束了。

            你也許在想,應該有什么好的管理線程的方法,而不是在主線程里做一個額外的延時 秒的操作。因為這樣一來,我們的總的運行時間并不比單線程的版本來得少。而且,像這樣使用 sleep()函數做線程的同步操作是不可靠的。如果我們的循環的執行時間不能事先確定的話,那怎么辦呢?這可能造成主線程過早或過晚退出。這就是鎖的用武之地了。

           

          mtsleep2.py

          復制代碼
          #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 =[]     #以loops數組創建列表,并賦值給nloops     nloops = range(len(loops))                for i in nloops:         lock = thread.allocate_lock()         #鎖定         lock.acquire()         #追加到locks[]數組中          locks.append(lock)      #執行多線程     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()
          復制代碼

          thread.allocate_lock() 

            返回一個新的鎖定對象。

          acquire() /release() 

            一個原始的鎖有兩種狀態,鎖定與解鎖,分別對應acquire()release() 方法。

          range()

            range()函數來創建列表包含算術級數。

          range(len(loops))理解:

          復制代碼
          >>> aa= "hello"  #長度計算 >>> len(aa) 5  #創建列表 >>> range(len(aa)) [0, 1, 2, 3, 4]  #循環輸出列表元素 >>> for a in range(len(aa)):     print a       0 1 2 3 4
          復制代碼

            我們先調用 thread.allocate_lock()函數創建一個鎖的列表,并分別調用各個鎖的 acquire()函數獲得鎖。獲得鎖表示“把鎖鎖上”。鎖上后,我們就把鎖放到鎖列表 locks 中。

            下一個循環創建線程,每個線程都用各自的循環號,睡眠時間和鎖為參數去調用 loop()函數。為什么我們不在創建鎖的循環里創建線程呢?有以下幾個原因:(1) 我們想到實現線程的同步,所以要讓“所有的馬同時沖出柵欄”。(2) 獲取鎖要花一些時間,如果你的線程退出得“太快”,可能會導致還沒有獲得鎖,線程就已經結束了的情況。

            在線程結束的時候,線程要自己去做解鎖操作。最后一個循環只是坐在那一直等(達到暫停主線程的目的),直到兩個鎖都被解鎖為止才繼續運行。

          mtsleep2.py運行結果:

          starting at: Mon Dec 23 20:57:26 2013 start loop start loop0  1at:  at:Mon Dec 23 20:57:26 2013  Mon Dec 23 20:57:26 2013 loop 1 done at: Mon Dec 23 20:57:28 2013 loop 0 done at: Mon Dec 23 20:57:30 2013 all end: Mon Dec 23 20:57:30 2013

           

           

           7.2.1、threading模塊

            我們應該避免使用thread模塊,原因是它不支持守護線程。當主線程退出時,所有的子線程不論它們是否還在工作,都會被強行退出。有時我們并不期望這種行為,這時就引入了守護線程的概念。threading模塊則支持守護線程。

          mtsleep3.py

          復制代碼
          #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))               #創建線程     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()
          復制代碼

          運行結果:

          starting at: Mon Dec 23 22:58:55 2013 start loop 0 at: Mon Dec 23 22:58:55 2013 start loop 1 at: Mon Dec 23 22:58:55 2013 loop 1 done at: Mon Dec 23 22:58:57 2013 loop 0 done at: Mon Dec 23 22:58:59 2013 all end: Mon Dec 23 22:58:59 2013

          start()

            開始線程活動

          join()

            等待線程終止

           

            所有的線程都創建了之后,再一起調用 start()函數啟動,而不是創建一個啟動一個。而且,不用再管理一堆鎖(分配鎖,獲得鎖,釋放鎖,檢查鎖的狀態等),只要簡單地對每個線程調用 join()函數就可以了。

          join()會等到線程結束,或者在給了 timeout 參數的時候,等到超時為止。join()的另一個比較重要的方面是它可以完全不用調用。一旦線程啟動后,就會一直運行,直到線程的函數結束,退出為止。

           

          使用可調用的類

           mtsleep4.py

          復制代碼
          #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 "seart loop",nloop,'at:',ctime()     sleep(nsec)     print 'loop',nloop,'done at:',ctime()  def main():     print 'starting at:',ctime()     threads=[]     nloops = range(len(loops))      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()
          復制代碼

           運行結果:

          starting at: Tue Dec 24 16:39:16 2013 seart loop 0 at: Tue Dec 24 16:39:16 2013 seart loop 1 at: Tue Dec 24 16:39:16 2013 loop 1 done at: Tue Dec 24 16:39:18 2013 loop 0 done at: Tue Dec 24 16:39:20 2013 all end: Tue Dec 24 16:39:20 2013

          創建新線程的時候,Thread 對象會調用我們的ThreadFunc 對象,這時會用到一個特殊函數__call__()。由于我們已經有了要用的參數,所以就不用再傳到 Thread()的構造函數中。由于我們有一個參數的元組,這時要在代碼中使用 apply()函數。

          我們傳了一個可調用的類(的實例),而不是僅傳一個函數。

          __init__()

          方法在類的一個對象被建立時運行。這個方法可以用來對你的對象做一些初始化

          apply()

          apply(func [, args [, kwargs ]]) 函數用于當函數參數已經存在于一個元組或字典中時,間接地調用函數。args是一個包含將要提供給函數的按位置傳遞的參數的元組。如果省略了args,任何參數都不會被傳遞,kwargs是一個包含關鍵字參數的字典。

          apply() 用法:

          復制代碼
          #不帶參數的方法 >>> def say():     print 'say in'  >>> apply(say) say in  #函數只帶元組的參數 >>> def say(a,b):     print a,b  >>> apply(say,('hello','蟲師')) hello 蟲師  #函數帶關鍵字參數 >>> def say(a=1,b=2):     print a,b       >>> def haha(**kw):     apply(say,(),kw)       >>> haha(a='a',b='b') a b
          復制代碼

           

          posted on 2014-02-27 14:39 順其自然EVO 閱讀(229) 評論(0)  編輯  收藏 所屬分類: python

          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 马关县| 玛纳斯县| 类乌齐县| 宁波市| 温宿县| 曲阳县| 泰宁县| 新和县| 宁蒗| 屯昌县| 搜索| 明水县| 义马市| 获嘉县| 宁乡县| 阳春市| 水城县| 万宁市| 连城县| 徐州市| 阿勒泰市| 凤山市| 瑞丽市| 吉首市| 兴国县| 阜宁县| 韩城市| 无锡市| 紫阳县| 吕梁市| 水富县| 健康| 象州县| 阿克陶县| 吴旗县| 苗栗市| 辽宁省| 广汉市| 南溪县| 宝兴县| 屯昌县|