33 python Threading模組與執行緒 執行緒池 GIL鎖
阿新 • • 發佈:2018-12-03
---恢復內容開始---
一 python Threading模組與執行緒
multiprocess模組完全模仿了threading模組的介面,二者在使用層面有較大的相似處。
1. 執行緒的建立
from threading import Thread def func(m): print(m) if __name__ == '__main__': f = Thread(target=func,args=(1,)) #建立一個執行緒物件 f.start() print('主程序結束')方式一
from方式二threading import Thread class Mythread(Thread): def __init__(self,m): super().__init__()#繼承Thread模組的init self.m = m def run(self): print('拉拉愛了') def norun(self): #還可以寫其他的方法 print('啦啊的') if __name__ == '__main__': m = Mythread('e') #傳遞自己的變數 m.start() m.norun()
2.多執行緒和多程序執行的效率對比
ort time from threading import Thread from multiprocessing import Process def func(): pass if __name__ == '__main__': t_list = [] t_s_t = time.time() for i in range(100): t = Thread(target=func,) t_list.append(t) t.start() [tt.join()效率對比for tt in t_list]#等待子程式 t_e_t = time.time() t_dif_t = t_e_t - t_s_t p_list = [] p_s_t = time.time() for i in range(100): p = Process(target=func,) p_list.append(p) p.start() [pp.join() for pp in p_list]#等待子程式 p_e_t = time.time() p_dif_t = p_e_t - p_s_t print('多執行緒的時間>>>',t_dif_t)#0.025949478149414062 print('多程序的時間>>>',p_dif_t)#7.810645341873169 print('主執行緒結束')
3 多執行緒資料共享
import time from threading import Thread num = 100 def func(): # time.sleep(3) global num tep = num time.sleep(0.001) tep = tep - 1 num = tep # num -= 1 if __name__ == '__main__': t_list = [] for i in range(100): t = Thread(target=func,) t_list.append(t) t.start() [tt.join() for tt in t_list] print('主執行緒的num',num) #87 由於共享時會爭搶資料並沒有變為0驗證
import time from threading import Thread,Lock num = 100 def func(tl): time.sleep(1) global num tl.acquire() tep = num time.sleep(0.001) tep = tep - 1 num = tep tl.release() if __name__ == '__main__': tl = Lock() t_list = [] for i in range(10): t = Thread(target=func,args=(tl,)) t_list.append(t) t.start() [tt.join() for tt in t_list] # t.join() print('主執行緒的num',num)枷鎖解決資料共享不安全
4 守護執行緒守護程序
import time from threading import Thread from multiprocessing import Process def func1(): time.sleep(3) print('任務1結束') def func2(): time.sleep(2) print('任務2結束') if __name__ == '__main__': p1 = Process(target=func1,) p2 = Process(target=func2,) #守護程序:主程序程式碼結束,守護程序結束,由於程式具有回收機制,所以要等待非守護子程序執行完,才結束。 p1.daemon = True # p2.daemon = True p1.start() p2.start() t1 = Thread(target=func1,) t2 = Thread(target=func2,) t1.daemon = True t2.setDaemon(True) #將t2設定為守護執行緒 #守護執行緒:主程式等所有非守護執行緒結束才結束 t1.setDaemon(True) #將t1設定為守護執行緒 t1.start() t2.start() print('主程序結束')守護執行緒
5 訊號量
import time import random from threading import Thread,Semaphore def func1(i,s): s.acquire() # time.sleep(1) print('客官%s裡邊請~~'%i) time.sleep(random.randint(1, 3)) s.release() if __name__ == '__main__': s = Semaphore(4) for i in range(10): t = Thread(target=func1,args=(i,s)) t.start()訊號量
6 事件
事件的from threading import Thread,Event e = Event() #預設是False, # print(e.isSet()) print('開始等啦') e.set() #將事件物件的狀態改為True print(e.isSet()) # e.clear() #將e的狀態改為False e.wait() #如果e的狀態為False,就在這裡阻塞 print('大哥,還沒完事兒,你行')
7 執行緒佇列
import queue #先進先出佇列 q = queue.Queue(3) q.put('first') q.put('second') q.put(3) # q.put(6) #佇列長度為3 當放過超過這個長度時程式就會一直等待前面的元素被拿 # 此時就可以用put_nowait()配合try來使用 try: q.put_nowait(3) except: print('佇列滿了') # print(q.qsize())#佇列長度 print(q.get()) print(q.get()) print(q.get()) try: print(q.get_nowait()) except: print('佇列沒有了') import queue #先進後出佇列 q = queue.LifoQueue() q.put(1) q.put(2) q.put(3) print(q.get()) #3 print(q.get())#2 print(q.get())#1 import queue q = queue.PriorityQueue()#自定義排序 q.put((0,10)) q.put((-1,4)) q.put((6,9)) print(q.get())#(-1, 4) print(q.get())#(0, 10) print(q.get())#(6, 9)幾種佇列
8 執行緒池
import time from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor #上面匯入的是執行緒池和程序池(另外一種匯入法) from multiprocessing import Pool def func(n): time.sleep(1) # print(n*n) return n*n if __name__ == '__main__': t = ThreadPoolExecutor(4) # p = ProcessPoolExecutor(4) #建立程序池,其他的方法完全一樣 res_lis = [] for i in range(10): res = t.submit(func,i) #非同步提交執行緒,拿到結果物件 # print(res.result()) #等待結果阻塞,拿到就再執行下一個迴圈,序列 res_lis.append(res) t.shutdown() # 放在此處此時所有結果物件都有結果直接全部拿到 for res in res_lis: print(res.result()) # t.shutdown() # 等待子執行緒結束,和程序裡面close()+join()差不多,此時上面for結果會四個四個列印結果 print('主程序結束') # 程序池 # if __name__ == '__main__': # p = Pool(4) # for i in range(10): # res = p.apply_async(func,(i,)) # print(res.get())執行緒池和程序池建立方法
9 執行緒池的map方法
import time from concurrent.futures import ThreadPoolExecutor def func(n): # print(n) time.sleep(1) return n*n if __name__ == '__main__': t = ThreadPoolExecutor(4) res = t.map(func,range(10))#只是提交任務主程式不會等待 for m in res: #生成器物件 print(m) print('主程序結束')執行緒池map返回值為一個生成器
10 執行緒池,程序池的返回函式
import time from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from multiprocessing import Pool def func(n): return n*n def call_back(i): print('>>>>',i) print(i) if __name__ == '__main__': # p = Pool(4) t = ThreadPoolExecutor(4) p = ProcessPoolExecutor(4) lis = [] for i in range(10): #執行緒池的方法 res = t.submit(func,i).add_done_callback(call_back) lis.append(res) #返回的都是結果物件 for i in lis: print(i.result()) for i in range(10): # 程序池的方法 res = t.submit(func,i).add_done_callback(call_back) for i in range(10): res = p.apply_async(func,(i,),callback=call_back) print(res.get()) # p.close() # p.join() print('sssss')call_back
二 GIL鎖
Gil鎖(Global Interpreter Lock)
python全域性直譯器鎖,有了這個鎖的存在,python直譯器在同一時間內只能讓一個程序中的一個執行緒去執行,這樣python的多執行緒就無法利用多核優勢,但是這並不是python語言本身的缺點,是直譯器的缺點,這個問題只存在於Cpython解釋其中,像Jpython就沒有。但是Cpthon是python官方直譯器(算目前執行效率最高的吧),所以多數人都以為Gil鎖是python語言的弊端。
過程解釋:
1、載入python直譯器程式碼
2、載入自己的py檔案
3、py檔案作為引數傳給直譯器(因為有GIL鎖,一次只能一個執行緒進入)
4、直譯器將py檔案編譯成.pyc位元組碼檔案
5、直譯器通過虛擬機器將位元組碼檔案轉為二進位制檔案
6、二進位制檔案等待cpu呼叫
---恢復內容結束---