Python之執行緒
一、執行緒的起源
1,程序
之前我們已經瞭解了作業系統中程序的概念,程式並不能單獨執行,只有將程式裝載到記憶體中,系統為其分配資源才能執行,而這種執行的程式就稱之為程序。程式和程序的區別就在於:程式是指令的集合,它是程序執行的靜態描述文字;程序是程式的一次活動,屬於動態概念。在多道程式設計中,我們允許多個程式同時載入到記憶體中,在作業系統的排程下,可以實現併發的執行。這樣的設計大大提高了CPU的利用率。
2,為什麼還出現執行緒
例子:pycharm三個任務:鍵盤輸入、螢幕輸出、自動儲存硬碟,如果三個任務是同步工作的,那在鍵盤輸入的時候我們就看不到螢幕輸入,而我們需要在鍵盤輸入的時候同時在螢幕上顯示,還能在硬碟儲存。方案一,此時我們可以開三個程序來完成,三個程序之間還要通過程序通訊的介質幫助完成。方案二,其實我們還可以用執行緒來完成,此時我們可以在一個程序中開三個執行緒,由於執行緒間是資源共享的,所以不用藉助介質就能完成資料交換。我們對比兩種方案,方案一要開三個程序,如果有10000個任務,那就要開10000個程序,開程序很佔記憶體的,而且開程序很耗時間的,還要藉助介質才能實現通訊,而方案就不一樣了,只需開一個程序,節省了記憶體空間,縮短了時間,自身就可以實現資料共享,那肯定選擇方案二,從而就凸顯了執行緒的必要性。
3,執行緒的出現
隨著計算機技術的發展,程序出現了很多弊端,一是由於程序是資源擁有者,建立、撤銷與切換存在較大的時空開銷,因此引入輕型程序;二是由於對稱多處理機出現,可以滿足多個執行單位,二多個程序並行開銷過大,出現了能獨立執行的基本單位——執行緒,程序是資源分配的最小單位,執行緒是CPU排程的最小單位,每個程序中至少有一個執行緒,程序只是把資源集中到一起,而執行緒才是CPU上的執行單位。
4,執行緒與程序的關係
執行緒就是程序的組成單元,每一個程序至少有一個執行緒,同一個程序裡的多個執行緒,可以共享程序裡的資源,而且執行緒間切換比程序間切換快很多,程序不是一個可執行的實體,真正去執行程式的是執行緒,可以理解程序解釋裝執行緒的容器。
二,執行緒的建立方法
由於執行緒誕生於程序,所以說執行緒的建立和程序一模一樣,只是引用的模組不一樣而已。
1,方法一
from threading import Thread#和程序相比,就是執行緒引入的是Thread模組 def fun1(i): print('你是%s'%(i)) if __name__ == '__main__': t=Thread(target=fun1,args=(1,)) t.start() print('dddddddd')
2,方法二
from threading import Thread class Mythread(Thread): def __init__(self,nn): super().__init__() self.nn=nn def run(self): print('nishi%s'%self.nn) if __name__ == '__main__': t=Mythread('haha') t.start() print('dfssd')
三、多程序與多執行緒的效率對比
from multiprocessing import Process from threading import Thread import time def fun(): print('ffff') if __name__ == '__main__': l1=[] t_s_t=time.time() for i in range(100): t=Thread(target=fun,) l1.append(t) t.start() [tt.join() for tt in l1] t_e_t=time.time() l2 = [] p_s_t = time.time() for i in range(100): p = Process(target=fun, ) l1.append(p) p.start() [pp.join() for pp in l2] p_e_t = time.time() print('執行緒',t_e_t-t_s_t) print('程序',p_e_t-p_s_t) 執行緒 0.04086899757385254 程序 3.268401861190796
從上面的結果看,執行緒的效率比程序高很多,這主要是建立、銷燬程序和程序間切換太耗時間。
四、執行緒的其他方法
from threading import Thread,current_thread import threading,time def fun(i): time.sleep(2) print('我是%s號'%i) print('%s'%current_thread().getName())#獲取執行緒的name print('%s'%current_thread().ident)#獲取執行緒的id if __name__ == '__main__': for i in range(10): t=Thread(target=fun,args=(i,)) t.start() print(threading.enumerate())#返回一個正在執行執行緒的列表 print(threading.active_count())#返回正在執行執行緒的數量
五、死鎖現象
from threading import Thread,Lock,RLock import time def fun(loa,lob): loa.acquire() time.sleep(1) print('aaaaa') lob.acquire() print('bbbbb') lob.release() loa.release() def fun1(loa,lob): lob.acquire() time.sleep(1) print('cccccc') loa.acquire() print('ddddd') loa.release() lob.release() if __name__ == '__main__': # loa=Lock()#當我們用Lock時就會出現死鎖現象,由於是非同步執行的,fun1拿到loa,fun2拿到lob,然後fun1再去拿lob,fun2再去拿loa,但現在兩把鎖都被對方拿著,還沒釋放,從而形成死鎖 # lob=Lock() loa=lob=RLock()#當我們用Rlock時,若fun1先搶到,就必須等fun1用完,fun2才能拿到,這稱為遞迴鎖 t1=Thread(target=fun,args=(loa,lob)) t2=Thread(target=fun1,args=(loa,lob)) t1.start() t2.start()
六、主程序和主執行緒的結束標誌
主程序在主程序的程式碼執行完就結束,而主執行緒要等到在同一程序中的非守護執行緒程式碼執行完畢才結束。
主程序的結束標誌 from multiprocessing import Process import time def fun1(): time.sleep(2) print('我是fun1') def fun2(): time.sleep(3) print('我是fun2') if __name__ == '__main__': p1=Process(target=fun1,) p2=Process(target=fun2,) p1.daemon=True#p1現在是守護程序,在主程序結束後,隨之結束 p1.start() p2.start() print('我是主程序')#主程序會在這句程式碼執行完後結束,p1也會跟著結束,雖說p1還沒執行完,但是p1直接被幹死了 結果如下 我是主程序 我是fun2
主執行緒結束標誌 from threading import Thread import time def fun1(): time.sleep(2) print('我是fun1') def fun2(): time.sleep(3) print('我是fun2') if __name__ == '__main__': t1=Thread(target=fun1,) t2=Thread(target=fun2,) t1.daemon=True#把t1設為守護執行緒 t1.start() t2.start() print('我是主執行緒')#這句程式碼執行完後,主執行緒還沒結束,主執行緒要等待非守護執行緒t2執行完畢後才結束,因為t2執行時間比t1長,所以這次t1也會執行完畢