程式扎記: [ Python 常見問題 ] Python 線程使用介紹

標籤

2012年5月24日 星期四

[ Python 常見問題 ] Python 線程使用介紹

參考自 這裡 
Preface : 
再編程的過程中, 很多時候為了 Performance 考量會採用 Multi-thread 的方式來提升程式的 throughput. 這邊我們要來簡單介紹一下如何在 Python 使用線程. 

Thread Objects : 
在 Python 可以使用模組 threading 來進行多線程的設計, 在該模組中有個類別 Thread 用來代表線程本身. 接著我們來看看這個類別的用法. 

首先當 Thread 類別被實例化, 你可以呼叫物件上面的方法 start() 來啟動該線程, 事實上該方法會再呼叫方法 run() (Method representing the thread’s activity.). 一旦線程啟動, 它的狀態會變成 "alive" ; 當執行完畢 run() 後狀態便不在是 "alive". 你可以使用方法 is_alive() 來檢視該線程是否停留在 "alive" 狀態. 

當線程呼叫其他線程物件上的方法 join(), 這會讓呼叫 join() 方法的線程被 blocked, 一直到被呼叫 join() 的線程結束為止. 

另外每個線程都有自己的名字. 線程的名字可以透過建構子賦予, 且可以透過線程物件上的 name 屬性取得. 

另外線程可以被標示程 "daemon thread". 用途是當剩下的線程都是 "daemon thread" 時, 主程式可以成功 exit 而不會等待這些 "daemon thread". 而這個屬性是會被子線程繼承下去, 而你可以透過 daemon 屬性進行設定. 

Usage : 
考慮我們定義一個工作類別 Job : 
  1. class Job:  
  2.      def __init__(self, name):  
  3.              self.name = name  
  4.      def do(self):  
  5.              time.sleep(2)  
  6.              print("\t[Info] Job({0}) is done!".format(self.name))  
接著我們實例化多個 Job 物件並存到 Queue 中. 並分別使用 Single thread 與 Multi-thread 來看看個別所花費的時間. 首先來建立 Job 物件並放到 Queue 中 : 
 

如果是 Single thread, 我們便可以用下面代碼一次一個從 Queue 取出 Job 並執行 : 
  1. st = datetime.datetime.now()  
  2. while que.qsize() > 0:  
  3.         job = que.get()  
  4.         job.do()  
  5.   
  6. td = datetime.datetime.now() - st  
  7. print("\t[Info] Spending time={0}!".format(td))  
因為一個 Job 會花兩秒, 共 20 個 Jobs, 所以可以預期的是花費時間約是 40 秒 : 
 

如果使用 Multi-thread 的話, 可以參考下面代碼, 共開 3 支線程 : 
  1. import queue, time, threading, datetime  
  2.   
  3. class Job:    
  4.      def __init__(self, name):    
  5.              self.name = name    
  6.      def do(self):    
  7.              time.sleep(2)    
  8.              print("\t[Info] Job({0}) is done!".format(self.name))  
  9.   
  10. que = queue.Queue()  
  11. for i in range(20):  
  12.         que.put(Job(str(i+1)))  
  13.   
  14. print("\t[Info] Queue size={0}...".format(que.qsize()))  
  15.   
  16. def doJob(*args):  
  17.      queue = args[0]  
  18.      while queue.qsize() > 0:  
  19.           job = queue.get()  
  20.           job.do()  
  21.   
  22. # Open three threads  
  23. thd1 = threading.Thread(target=doJob, name='Thd1', args=(que,))  
  24. thd2 = threading.Thread(target=doJob, name='Thd2', args=(que,))  
  25. thd3 = threading.Thread(target=doJob, name='Thd3', args=(que,))  
  26.   
  27. # Start activity to digest queue.  
  28. st = datetime.datetime.now()  
  29. thd1.start()  
  30. thd2.start()  
  31. thd3.start()  
  32.   
  33. # Wait for all threads to terminate.  
  34. while thd1.is_alive() or thd2.is_alive() or thd3.is_alive():  
  35.      time.sleep(1)    
  36.   
  37. td = datetime.datetime.now() - st  
  38. print("\t[Info] Spending time={0}!".format(td))  
可以發現使用 Multi-thread 情況下, 消化完整個 20 個 Jobs 只需要 15 秒左右, 遠小於單線程的 40 秒 : 
 

Supplement : 
tutorialspoint > Python - while Loop Statements 
Queue – A thread-safe FIFO implementation

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!