python -- 多線程編程
阿新 • • 發佈:2017-06-08
res iss 默認 按鈕 turn exe 能夠 內存 並不是
多線程類似於同時執行多個不同程序,多線程運行有如下優點:
- 使用線程可以把占據長時間的程序中的任務放到後臺去處理。
- 用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度
- 程序的運行速度可能加快
- 在一些等待的任務實現上如用戶輸入、文件讀寫和網絡收發數據等,線程就比較有用了。在這種情況下我們可以釋放一些珍貴的資源如內存占用等等。
線程在執行過程中與進程還是有區別的。每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
每個線程都有他自己的一組CPU寄存器,稱為線程的上下文,該上下文反映了線程上次運行該線程的CPU寄存器的狀態。
指令指針和堆棧指針寄存器是線程上下文中兩個最重要的寄存器,線程總是在進程得到上下文中運行的,這些地址都用於標誌擁有線程的進程地址空間中的內存。
- 線程可以被搶占(中斷)。
- 在其他線程正在運行時,線程可以暫時擱置(也稱為睡眠) -- 這就是線程的退讓。
python中的多線程
多線程之間是共享內存的,而且是可以直接通信的。
1、多線程實現
1 ‘‘‘1、直接實現(最常用)‘‘‘ 2 import threading 3 import time 4 5 def hello(num): 6 print("This threading is no [%s]" %num)7 time.sleep(2) 8 9 if __name__ == ‘__main__‘: 10 ‘‘‘ 11 t1 = threading.Thread(target=hello,args=[1,]) #實例化一個線程,後面參數為列表,只有一個元素時,要有‘,‘ 12 t2 = threading.Thread(target=hello,args=[2,]) 13 14 t1.start() #上面只是實例化,這裏才是啟動線程 15 t2.start() 16 t1.join() 17 t2.join()18 print(‘------main------‘) 19 20 以上在沒有t1.join()、t2.join()時,後面那句直接打印。因為啟動線程後,主線程和兩個子線程 21 相互獨立, print(‘------main------‘)是屬於主線程的,不會等待子線程結束才打印 22 23 t1.join() 的作用是:阻塞,等待線程t1結束後猜結束父線程 24 ‘‘‘ 25 26 #若有多個線程,對上面代碼改進: 27 t_list = [] 28 for i in range(10): 29 t = threading.Thread(target=hello,args=[i,]) 30 t.start() 31 t_list.append(t) 32 33 for i in t_list: 34 i.join() 35 36 print(‘------main------‘) 37 38 39 ‘‘‘2、自定義類實現多線程‘‘‘ 40 import threading 41 import time 42 43 class MyThread(threading.Thread): 44 def __init__(self,num): 45 super(MyThread,self).__init__() #繼承父類的構造函數 46 self.num = num 47 48 #在自定義線程類裏面,必須有這個run方法 49 #這個run默認是每個線程調用start函數後執行的函數 50 def run(self): 51 print("This threading is no [%s]" %self.num) 52 time.sleep(2) 53 54 55 t1 = MyThread(1) 56 t2 = MyThread(2) 57 t1.start() 58 t2.start() 59 t1.join() 60 t2.join() 61 print("父線程執行結束~") 62 63 64 ‘‘‘守護線程‘‘‘ 65 ‘‘‘ 66 setDaemon 設置守護線程 eg:t.setDaemon(True) 67 ‘‘‘ 68 import time 69 import threading 70 71 def run(n): 72 print("[%s] ------running------\n" %n) 73 time.sleep(2) 74 print(‘---done---‘) 75 76 def main(): 77 for i in range(5): 78 t = threading.Thread(target=run,args=[i,]) 79 t.start() 80 print("starting thread",t.getName()) 81 t.join(1) 82 83 m = threading.Thread(target=main,args=[]) 84 #將m線程設置為Daemon線程,它做為程序主線程的守護線程,當主線程退出時,m線程也會退出,由m啟動的其它子線程會同時退出,不管是否執行完任務 85 m.setDaemon(True) 86 m.start() 87 m.join(2) 88 print("----main thread done---")
註意:python的多線程是通過c語言的接口調用的系統原生的線程,所以在線程調用後,python就是去了對線程的控制能力,當線程結束後會把執行結果返回給python。
2、GIL與線程鎖
GIL鎖:全局解釋器鎖,它是解釋器層次的,作用是控制每次只能有一個python線程在操作系統中運行
線程鎖(互斥鎖):是在解釋器之上控制同一時間只能一個線程修改指定變量的鎖
在多線程時,若多個線程都是修改同一份數據,那麽就要對修改數據的代碼部分加上線程鎖
這樣能使在同一時刻,只有一個線程在修改該數據,這樣才能達到預想的效果
1 import threading 2 import time 3 4 def addNum(): 5 global num 6 print("--get num:",num) 7 time.sleep(1) 8 lock.acquire() #加鎖 9 num -= 1 #修改變量 10 lock.release() #解鎖 加鎖後必須要解鎖,不然程序就死了 11 12 num = 100 13 thread_list = [] 14 lock = threading.Lock() #實例化一個線程鎖 15 16 for i in range(100): 17 t = threading.Thread(target=addNum) 18 t.start() 19 thread_list.append(i) 20 21 for i in thread_list: #等待所有線程都執行完畢 22 #t.join(timeout=3) #註意:這裏設置了timeout後就不再是阻塞狀態,而且,並不是等待3s... 23 t.join() #作用:只要子線程t還沒執行結束,這裏就阻塞,父線程就不能退出(父線程就是執行腳本這個) 24 25 print(‘finally num:‘,num) 26 ‘‘‘ 27 沒加鎖時,各線程執行後可能會覆蓋其他線程的結果,導致結果是隨機的 28 加鎖後,每次都只有一個線程在操作數據,所以結果就是確定的 29 ‘‘‘ 30 print(‘All of thread was exec over~‘)
3、遞歸鎖
1 #!/usr/bin/env python 2 #coding:utf-8 3 4 ‘‘‘ 5 遞歸鎖:就是大鎖裏面還要包含子鎖 6 ‘‘‘ 7 import threading,time 8 9 def run1(): 10 print("grab the first data") 11 rlock.acquire() #捕獲(加鎖) 12 global num1 13 num1 += 1 14 rlock.release() #釋放(去鎖) 15 return num1 16 17 def run2(): 18 print("geab the second data") 19 rlock.acquire() 20 global num2 21 num2 += 1 22 rlock.release() 23 return num2 24 25 def run3(): 26 rlock.acquire() 27 res1 = run1() 28 print("------btween run1 and run2------") 29 res2 = run2() 30 rlock.release() 31 print("res1:%s , res2: %s" %(res1,res2)) 32 33 if __name__ == "__main__": 34 num1,num2 = 0,0 35 rlock = threading.RLock() #實例化一個遞歸鎖 36 for i in range(10): 37 t = threading.Thread(target=run3) 38 t.start() 39 40 while threading.active_count() != 1: 41 print("剩余線程個數:",threading.active_count()) 42 else: 43 print("剩余線程個數:",threading.active_count()) 44 print(‘------all threads done------‘) 45 print("最後 num1:%s num2: %s" %(num1,num2))
4、信號量
1 #!/usr/bin/env python 2 #coding:utf-8 3 ‘‘‘ 4 信號量:互斥鎖同時只允許一個線程更改數據,而Semaphore(信號量)是同時允許一定數量的線程更改數據 5 ‘‘‘ 6 import threading,time 7 8 def run(n): 9 semaphore.acquire() 10 time.sleep(1) 11 print("run the thread: %s\n" %n) 12 semaphore.release() 13 14 if __name__ == ‘__main__‘: 15 16 semaphore = threading.BoundedSemaphore(3) #最多允許3個線程同時運行 17 for i in range(20): 18 t = threading.Thread(target=run,args=[i,]) 19 t.start() 20 21 while threading.active_count() != 1: 22 #print(‘當前剩余線程數:‘,threading.active_count()) 23 pass 24 else: 25 print("------ all threads done ------") 26
5、接收線程返回的數據
1 #!/usr/bin/env python 2 # coding:utf-8 3 import time 4 import threading 5 6 data = [] 7 def func(n): 8 time.sleep(3) 9 data.append(n**n) 10 print(‘hello‘,n) 11 return n**n 12 13 thread_list = [] 14 for i in range(20): 15 #t = threading.Thread(target=func,args=[i,]) #這裏傳參時,參數以列表形式後面可以加‘,‘,也可以不加;以元組形式必須加 16 t = threading.Thread(target=func,args=(i,)) 17 t.start() 18 thread_list.append(t) 19 20 #for i in thread_list: 21 #i.join() 22 #print(‘hello ‘,i) 23 24 #print(thread_list) 25 print(data) 26 print(‘----main thread end----‘)
6、event模塊
1 #!/usr/bin/env python 2 # coding:utf-8 3 4 ‘‘‘ 5 通過Event來實現兩個或多個線程間的交互,下面是一個紅綠燈的例子,即起動一個線程做交通指揮燈,生成幾個線程做車輛,車輛行駛按紅燈停,綠燈行的規則。 6 個人理解: 7 通過Event實例化一個對象,這個對象用set方法設置一直flag,所有線程都能訪問flag,並根據flag不同的值做不同的處理 8 ‘‘‘ 9 import threading 10 import time 11 12 13 def light(): 14 if not event.isSet(): 15 event.set() # set後,wait就不阻塞 16 count = 0 17 while True: 18 if count < 10: 19 print(‘ \033[42;1m--green light on---\033[0m‘) 20 elif count < 13: 21 print(‘ \033[43;1m--yellow light on---\033[0m ‘) 22 elif count < 20: 23 if event.isSet(): 24 event.clear() 25 print(‘ \033[41;1m--red light on---\033[0m ‘) 26 else: 27 count = 0 28 event.set() 29 time.sleep(1) 30 count += 1 31 32 33 def car(n): 34 35 ‘‘‘ 36 :param n: 給車輛的編號 37 :return: 默認返回值是None 38 ‘‘‘ 39 40 while True: 41 time.sleep(1) 42 if event.isSet(): 43 print(‘car [%s] is running...‘ % n) 44 else: 45 print(‘car [%s] is waiting for the red light...‘ % n) 46 event.wait() 47 48 if __name__ == "__main__": 49 event = threading.Event() # 實例化一個Event對象 50 Light = threading.Thread(target=light) 51 Light.start() 52 for i in range(3): 53 Car = threading.Thread(target=car,args=(i,)) 54 Car.start()
python -- 多線程編程