【併發程式設計】多執行緒
目錄
一、什麼是執行緒
二、開啟執行緒的兩種方式
三、多執行緒與多程序的區別
四、守護執行緒
一、什麼是執行緒
1.1 概念
執行緒是程序的一個實體,是CPU排程和分派的基本單位,它是比程序更小的能獨立執行的基本單位。執行緒自己基本上不擁有系統資源,只擁有一點在執行中必不可少的資源(如程式計數器,一組暫存器和棧)但是它可與同屬一個程序的其他的執行緒共享程序所擁有的全部資源。一個執行緒可以建立和撤銷另一個執行緒;同一個程序中的多個執行緒之間可以併發執行。
1.2 程序和執行緒的區別
1、一個程式至少有一個程序,一個程序至少有一個執行緒。(程序可以理解成執行緒的容器)
2、程序在執行過程中擁有獨立的記憶體單元,而多個執行緒共享記憶體,從而極大地提高了程式的執行效率。
3、執行緒在執行過程中與程序還是有區別的。每個獨立的執行緒有一個程式執行的入口、順序執行序列和程式的出口。但是執行緒不能夠獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。
4、程序是具有一定獨立功能的程式關於某個資料集合上的一次執行活動,程序是系統進行資源分配和排程的一個獨立單位。
二、開啟執行緒的兩種方式
2.1 threading模組介紹
threading模組的介面與multiprocess模組很相像。二者在使用層面,有很大的相似性,因而不再詳細介紹。
2.2 開啟執行緒的兩種方式
方式一:呼叫內建的類
1 import time,random 2 from threading import Thread 3 4 5 def piao(name): 6 print("%s is piaoing" % name) 7 time.sleep(random.randrange(1,5))View Code8 print("%s piao end" % name) 9 10 11 if __name__ =="__main__": 12 t1 = Thread(target=piao,args=("egon",)) 13 14 t1.start() 15 print("主程序") #每開一個程序,預設有一個執行緒 16 #所以當前有一個程序一個執行緒
方式二:自定義類
1 import time 2 from threading import Thread 3 4 5View Codeclass MyThread(Thread): 6 def __init__(self,name): 7 super().__init__() 8 self.name = name 9 10 def run(self): 11 print("%s is piaoing" % self.name) 12 time.sleep(2) 13 print("%s is running" % self.name) 14 15 16 if __name__ == "__main__": 17 t1 = MyThread("egon") 18 t1.start() 19 print("主程序")
三、多執行緒與多程序的區別
1 建立程序的開銷遠大於執行緒,可利用time模組來對比所耗時間。
1 from threading import Thread 2 import time 3 4 def work(start): 5 stop = time.time() 6 print("開啟執行緒所用時間為%.5f秒" % (stop - start)) 7 8 9 if __name__ == '__main__': 10 start = time.time() 11 t=Thread(target=work,args=(start,)) 12 t.start() 13 14 15 #執行結果如下: 16 開啟執行緒所用時間為0.00050秒建立執行緒
1 from multiprocessing import Process 2 import time 3 4 def work(start): 5 stop = time.time() 6 print("開啟子程序所用時間為%.5f秒" % (stop - start)) 7 8 9 if __name__ == '__main__': 10 start = time.time() 11 p=Process(target=work,args=(start,)) 12 p.start() 13 14 15 #執行結果如下: 16 開啟子程序所用時間為0.14338秒建立程序
2 在主程序下開啟多個執行緒,各執行緒與主執行緒pid相同;而開啟多個程序,每個程序都用不同的pid。因為同一程序內多個執行緒共享該程序的記憶體空間,而各程序間記憶體空間相互隔離。
1 from threading import Thread 2 import os 3 4 def work(): 5 print('hello',os.getpid()) 6 7 if __name__ == '__main__': 8 t1=Thread(target=work) 9 t2=Thread(target=work) 10 t1.start() 11 t2.start() 12 print('主執行緒/主程序pid',os.getpid()) 13 14 執行結果如下: 15 hello 21188 16 hello 21188 17 主執行緒/主程序pid 21188多執行緒
1 from multiprocessing import Process 2 import os 3 4 def work(): 5 print('hello',os.getpid()) 6 7 if __name__ == '__main__': 8 p1=Process(target=work) 9 p2=Process(target=work) 10 p1.start() 11 p2.start() 12 print('主執行緒/主程序',os.getpid()) 13 14 15 #執行結果如下 16 主執行緒/主程序 22292 17 hello 1160 18 hello 23292多程序
四、守護執行緒
無論是程序還是執行緒,都遵循:守護xxx會等待主xxx執行完畢後被銷燬。需要強調的是:執行完畢並非終止執行。
1、對主程序來說,執行完畢指的是主程序程式碼執行完畢
2、對主執行緒來說,執行完畢指的是主執行緒所在的程序內所有非守護執行緒統統執行完畢,主執行緒才算執行完畢
即:
1、主程序在其程式碼結束後就已經算執行完畢(守護程序在此時就被回收),然後主程序會一直等非守護的子程序都執行完畢後回收子程序的資源(否則會產生殭屍程序)才會結束。
2、主執行緒在其他非守護執行緒執行完畢後才算執行完畢(守護執行緒在此時就被回收)。因為主執行緒的結束意味著程序的結束,程序整體的資源都將被回收,而程序必須保證非守護執行緒都執行完畢後才能結束。
驗證如下:
1 from threading import Thread 2 import time 3 4 def foo(): 5 print(123) 6 time.sleep(1) 7 print("end123") 8 9 def bar(): 10 print(456) 11 time.sleep(3) 12 print("end456") 13 14 if __name__ == '__main__': 15 t1=Thread(target=foo) 16 t2=Thread(target=bar) 17 18 t1.daemon=True 19 t1.start() 20 t2.start() 21 print("main-------") 22 23 24 #執行結果如下 25 123 26 456 27 main------- 28 end123 29 end456View Code
執行緒t1,t2洗後開啟,打印出123,456.緊接著主執行緒打印出main-------。此時,主執行緒需要等待非守護執行緒t2結束,在此期間,t1執行緒列印end123,然後t2列印end456