Python 基礎之-進程、線程
進程與線程
什麽是進程
程序並不能單獨運行,只有將程序裝載到內存中,系統為它分配資源才能運行,而這種執行的程序就稱之為進程。程序和進程的區別就在於:程序是指令的集合,它是進程運行的靜態描述文本;進程是程序的一次執行活動,屬於動態概念。
在多道編程中,我們允許多個程序同時加載到內存中,在操作系統的調度下,可以實現並發地執行。這是這樣的設計,大大提高了CPU的利用率。進程的出現讓每個用戶感覺到自己獨享CPU,因此,進程就是為了在CPU上實現多道編程而提出的。
有了進程為什麽還要線程?
進程有很多優點,它提供了多道編程,讓我們感覺我們每個人都擁有自己的CPU和其他資源,可以提高計算機的利用率。很多人就不理解了,既然進程這麽優秀,為什麽還要線程呢?其實,仔細觀察就會發現進程還是有很多缺陷的,主要體現在兩點上:
-
進程只能在一個時間幹一件事,如果想同時幹兩件事或多件事,進程就無能為力了。
-
進程在執行的過程中如果阻塞,例如等待輸入,整個進程就會掛起,即使進程中有些工作不依賴於輸入的數據,也將無法執行。
例如,我們在使用qq聊天, qq做為一個獨立進程如果同一時間只能幹一件事,那他如何實現在同一時刻 即能監聽鍵盤輸入、又能監聽其它人給你發的消息、同時還能把別人發的消息顯示在屏幕上呢?你會說,操作系統不是有分時麽?但我的親,分時是指在不同進程間的分時呀, 即操作系統處理一會你的qq任務,又切換到word文檔任務上了,每個cpu時間片分給你的qq程序時,你的qq還是只能同時幹一件事呀。
再直白一點, 一個操作系統就像是一個工廠,工廠裏面有很多個生產車間,不同的車間生產不同的產品,每個車間就相當於一個進程,且你的工廠又窮,供電不足,同一時間只能給一個車間供電,為了能讓所有車間都能同時生產,你的工廠的電工只能給不同的車間分時供電,但是輪到你的qq車間時,發現只有一個幹活的工人,結果生產效率極低,為了解決這個問題,應該怎麽辦呢?。。。。沒錯,你肯定想到了,就是多加幾個工人,讓幾個人工人並行工作,這每個工人,就是線程!
什麽是線程
線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以並發多個線程,每條線程並行執行不同的任務
進程和線程的區別
(1)進程是資源的分配和調度的一個獨立單元,而線程是CPU調度的基本單元 (2)同一個進程中可以包括多個線程,並且線程共享整個進程的資源(寄存器、堆棧、上下文),一個進程至少包括一個線程。 (3)進程的創建調用fork或者vfork,而線程的創建調用pthread_create,進程結束後它擁有的所有線程都將銷毀,而線程的結束不會影響同個進程中的其他線程的結束 (4)線程是輕量級的進程,它的創建和銷毀所需要的時間比進程小很多,所有操作系統中的執行功能都是創建線程去完成的 (5)線程中執行時一般都要進行同步和互斥,因為他們共享同一進程的所有資源 (6)線程有自己的私有屬性TCB,線程id,寄存器、硬件上下文,而進程也有自己的私有屬性進程控制塊PCB,這些私有屬性是不被共享的,用來標示一個進程或一個線程的標誌 Python threading模塊 線程有2種調用方式,如下: 直接調用importthreading import time def sayhi(num): # 定義每個線程要運行的函數 print("running on number:%s" % num) time.sleep(3) if __name__ == ‘__main__‘: t1 = threading.Thread(target=sayhi, args=(1,)) # 生成一個線程實例 t2 = threading.Thread(target=sayhi, args=(2,)) # 生成另一個線程實例 t1.start() # 啟動線程 t2.start() # 啟動另一個線程 print(t1.getName()) # 獲取線程名 print(t2.getName())
繼承式調用
import threading import time class MyThread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): # 定義每個線程要運行的函數 print("running on number:%s" % self.num) time.sleep(3) if __name__ == ‘__main__‘: t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start() print(t1.getName()) # 獲取線程名 print(t2.getName())
下面是一個對多線程的一個處理方法:(需要理解):
import threading import time def run(n): print("task: ",n) time.sleep(2) print("task done: ",n) start_time = time.time() for i in range(10): t = threading.Thread(target=run,args=(i,)) t.start() print("cost: ",time.time() - start_time)
運行結果如下所示:
是因為這個程序本身就是一個主線程,主線程又起了子線程,這時子線程和主線程已經沒關系了,相當於子線程和主線程是並行的。這就解釋了為什麽我的主線程啟動了子線程之後,沒有等子線程執行完畢,主線程就繼續往下走了。
但是現在有個問題,我們需要計算所有線程的執行時間,並且讓所有線程運行之後再運行主程序
這裏就需要用到線程裏的一個方法join()意思其實就是等待的意思代碼如下:
import threading import time def run(n): print("task: ",n) time.sleep(2) print("task done: ",n) start_time = time.time() t_obj = [] #存線程實例 for i in range(10): t = threading.Thread(target=run,args=(i,)) t.start() t_obj.append(t) #為了不阻塞後面線程的啟動,不在這裏join,先放到一個列表裏 for i in t_obj: #循環線程實例列表,等待所有線程執行完畢 i.join() print("all thread is done") print("cost: ",time.time() - start_time)
沒有加join的時候,主線程不會等子線程執行完畢再往下走,主線程和子線程的執行完全是並行的,沒有依賴關系,你執行,我也執行。但是,你會發現,最終退出的時候,主線程依然會等待所有的子線程執行完畢才退出程序。雖然不等你執行完畢才往下走,但是在程序退出之前,會默認還有一個join
但加了join的時候,主線程依賴子線程執行完畢之後, 再往下走,這是JOIN 的作用。
關於守護線程
如果將線程設置為守護線程,則主程序不會管線程是否執行完,只有主程序執行完畢之後,就會結束
代碼例子如下:
import threading import time def run(n): print("task: ",n) time.sleep(2) print("task done: ",n) start_time = time.time() for i in range(10): t = threading.Thread(target=run,args=(i,)) t.setDaemon(True) #把當前線程設置為守護線程 t.start() print("all thread is done",threading.current_thread(),threading.active_count()) print("cost: ",time.time() - start_time)
Python 基礎之-進程、線程