1. 程式人生 > >python -- 多線程編程

python -- 多線程編程

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 -- 多線程編程