Python多線程執行個體教程

來源:互聯網
上載者:User
本文以執行個體形式較為詳細的講解了Python的多線程,是Python程式設計中非常重要的知識點。分享給大家供大家參考之用。具體方法如下:

用過Python的人都會覺得Python的多線程很類似於Java的多線程機制,但是比JAVA的多線程更靈活。在早期的Python多線程實現中,採用了thread模組。例如:

from time import ctime,sleep from thread import start_new_thread def loop1():   print "enter loop1:",ctime();   sleep(3);   print "leave loop1:",ctime();  def loop2():   print "enter loop2:",ctime();   sleep(5);   print "leave loop2:",ctime();  def main():   print "main begin:",ctime();   start_new_thread(loop1, ());   start_new_thread(loop2,());   sleep(8);   print "main end:",ctime();  if __name__=="__main__":   main(); 

簡單介紹下這個代碼塊中的函數功能,sleep是線程睡眠時間,幾乎等價於JAVA中的Thread.sleep(millionseconds)

start_new_thread是執行個體化一個線程並啟動並執行方法,方法的第一個參數接受一個線程運行時所執行的函數對象,第二個參數是方法執行時所需要的參數,以一個元組的形式傳入。

這大概是最早期的Python多線程實現了,注意代碼中的main線程裡的sleep(8)。這裡的睡眠時間只能比3+5大,而不能小。如果小於這個時間,那麼main主線程會提前退出,導致無論其子線程是否是後台線程,都將會中斷,從而拋出線程中斷異常,類似於Java的ThreadInterruptException。這個致命的影響幾乎就是這個模組後期被拋棄的罪魁禍首。

當然在早期的Python多線程中,你可以利用加鎖的機制來避免出現這個情況。稍微改動下以上代碼:

import thread; from time import sleep,ctime; from random import choice #The first param means the thread number #The second param means how long it sleep #The third param means the Lock def loop(nloop,sec,lock):   print "Thread ",nloop," start and will sleep ",sec;   sleep(sec);   print "Thread ",nloop," end ",sec;   lock.release();  def main():   seconds=[4,2];   locks=[];   for i in range(len(seconds)) :     lock=thread.allocate_lock();     lock.acquire();     locks.append(lock);        print "main Thread begins:",ctime();   for i,lock in enumerate(locks):     thread.start_new_thread(loop,(i,choice(seconds),lock));   for lock in locks :     while lock.locked() :        pass;   print "main Thread ends:",ctime();  if __name__=="__main__" :   main(); 

這裡對Python線程運行時加入了鎖監控機制,介紹下紅色字型標誌的幾個方法(其實紅色字型中的lock實質是thread.lockType執行個體。

從以上介紹可以看出這個Lock類非常類似於JDK5.0中的java.util.concurrent.locks.Lock。不知道Doug Lea有沒有參與這個模組的開發,只是比JAVA中的LOCK類多了一個方法locked,用於檢測Lock對象是否還處於加鎖的狀態。

所以上一個例子的工作原理就是在啟動線程的時候,給每個線程都加了一把鎖,直到線程運行介紹,再釋放這個鎖。同時在Python的main線程中用一個while迴圈來不停的判斷每個線程鎖已釋放。這個方法雖然避免了最開始的例子中人為的時間控制,但是還不方便,高效。

所以在較新的Python版本中,都推薦使用threading模組。

看下threading模組的API,有過JAVA開發經驗的會發現它和java.lang.Thread類非常接近。這裡需要說的一點就是threading的run方法可以返回函數值,這點在用於跟蹤和判斷線程運行正常與否非常有作用。

threading模組支援三種方法來建立線程。而前兩種方式都與其Thread類有關。看下它的簡要說明:

class Thread(_Verbose) :    __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None) 

其中target指的是一個具體的函數,或者可調用的類執行個體(這裡指實現了__call__方法的類執行個體)

第一種方法:指定線程啟動並執行時候調用的函數。舉例如下:

from time import ctime,sleep import threading; from random import choice  def loop(number,sec):   print "Thread ",number," begins and will sleep ",sec," at ",ctime();   sleep(sec);   print "Thread ",number,"ends at ",ctime();    def main():   seconds=[2,4];   threads=[];   array=range(len(seconds));   for i in array :     t=threading.Thread(target=loop,args=(i,choice(seconds)));     threads.append(t);   print "main Thread begins at ",ctime();   for t in threads :     t.start();   for t in threads :     t.join();       print "main Thread ends at ",ctime();  if __name__=="__main__" :   main();  

這裡target指向了一個具體的函數對象,而args傳入了該方法調用時所必須的參數。這裡傳入了一個隨即的睡眠時間。其中thread.join表示要等待該線程終止,和java中的Thread.join(long millionseconds)作用一樣,如果不指定具體的時間的話,將會一直等待下去。

第二種方法就是指定一個可調用的類執行個體,實際上與前面一種非常的接近。如下所示:

from time import ctime,sleep import threading; from random import choice  class ThreadFunc(object):   def __init__(self,func,args,name):     self.func=func;     self.args=args;     self.name=name;        def __call__(self):     self.func(*self.args);  def loop(number,sec):   print "Thread ",number," begins and will sleep ",sec," at ",ctime();   sleep(sec);   print "Thread ",number,"ends at ",ctime();    def main():   seconds=[2,4];   threads=[];   array=range(len(seconds));   for i in array :     t=threading.Thread(target=ThreadFunc(loop,(i,choice(seconds)),loop.__name__));     threads.append(t);   print "main Thread begins at ",ctime();   for t in threads :     t.start();   for t in threads :     t.join();       print "main Thread ends at ",ctime();  if __name__=="__main__" :   main(); 

這裡只是將target指向從一個函數對象變成了一個可調用的類執行個體。

重點推薦下第三種方式,用繼承threading.Thread的方式來實現線程,有過Java多線程應用的朋友一定會對下面的例子非常熟悉。

from time import ctime,sleep import threading; from random import choice  class MyThread(threading.Thread):   def __init__(self,func,args,name):     super(MyThread,self).__init__();     self.func=func;     self.args=args;     self.name=name;          def run(self):     self.result=self.func(*self.args);    def getResult(self):     return self.result;    def loop(number,sec):   print "Thread ",number," begins and will sleep ",sec," at ",ctime();   sleep(sec);   print "Thread ",number,"ends at ",ctime();    def main():   seconds=[2,4];   threads=[];   array=range(len(seconds));   for i in array :     t=MyThread(loop,(i,choice(seconds)),loop.__name__);     threads.append(t);   print "main Thread begins at ",ctime();   for t in threads :     t.start();   for t in threads :     t.join();       print "main Thread ends at ",ctime();  if __name__=="__main__" :   main();   

從上面可以看出MyThread繼承了threading.Thread類,並在初始化方法中執行了必要的參數賦值。值得注意的是在Java類的繼承中,如果不顯示的指定調用父類的構造方法,那麼預設將調用父類的無參構造方法。而在Python中,就不會主動去調用。所以這裡需要顯示的調用父類的初始化方法。

希望本文所述對大家的Python程式設計有所協助。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.