其實自我感覺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  
 - 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有沒有參與這個模塊的開發,哈哈~~(純屬YY),只是比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中,就不會主動去調用。所以這里需要顯示的調用父類的初始化方法。
推薦一個網站:程序人生