七、並發編程(進程與執行緒)
- 2020 年 1 月 19 日
- 筆記
一、前言
進程即正在執行的一個過程。進程是對正在運行程式的一個抽象。
進程的概念起源於作業系統,是作業系統最核心的概念,也是作業系統提供的最古老也是最重要的抽象概念之一。作業系統的其他所有內容都是圍繞進程的概念展開的。
PS:即使可以利用的cpu只有一個(早期的電腦確實如此),也能保證支援(偽)並發的能力。將一個單獨的cpu變成多個虛擬的cpu(多道技術:時間多路復用和空間多路復用+硬體上支援隔離),沒有進程的抽象,現代電腦將不復存在。
作業系統的作用: 1:隱藏醜陋複雜的硬體介面,提供良好的抽象介面 2:管理、調度進程,並且將多個進程對硬體的競爭變得有序
二、並發編程之多進程
點我————————————-點我————————————-點我————————–
1. 什麼是進程 進程就是一個正在進行/運行的程式,換言之,進程指的是一個程式的運行過程 程式vs進程: 程式:只是一堆程式碼文件 進程:程式運行的過程才是進程 串列:一個任務完完整整地運行完畢,再執行下一個任務,按次序依次進行 串列看起來就是一個一個運行的:對 一個一個的運行就是串列:錯誤 並發(切換+保存狀態):多個任務看起來是同時運行,單核就可以實行並發 並行:多個任務是真正意義上的同時運行,只有多核才能實現並行 多道技術的產生背景:就是想要在單核下實現並發 ps: 現在的主機一般是多核,那麼每個核都會利用多道技術 有4個cpu,運行於cpu1的某個程式遇到io阻塞,會等到io結束再重新調度,會被調度到4個 cpu中的任意一個,具體由作業系統調度演算法決定 如何實現: 1. 空間上的復用:將記憶體分為幾部分,每個部分放入一個程式的數據, 這樣,同一時間記憶體中就有了多道程式的數據,為cpu在多個任務間切換做準備 2. 時間上的復用:多個進程共享cpu的時間 關鍵點就是cpu在多個任務之間進行切換 有兩種情況下會發生切換: 1. 一個任務佔用cpu時間過長(沒有遇到IO操作):會降低效率 1. 一個任務在運行的過程中遇到IO操作: 可以提升效率 2. 為何要用進程 要實現並發效果
同步非同步 and 阻塞非阻塞(重點)
同步
同步,就是在發出一個功能調用時,在沒有得到結果之前,該調用就不會返回。按照這個定義,其實絕大多數函數都是同步調用。但是一般而言,我們在說同步、非同步的時候,特指那些需要其他部件協作或者需要一定時間完成的任務。 舉例: 1. concurrent.futures.ProcessPoolExecutor().submit(func,).result() 2. concurrent.futures.ThreadPoolExecutor().submit(func,).result() 一提交便得到結果
非同步
非同步的概念和同步相對。當一個非同步功能調用發出後,調用者不能立刻得到結果。當該非同步功能完成後,通過狀態、通知或回調來通知調用者。如果非同步功能用狀態來通知,那麼調用者就需要每隔一定時間檢查一次,效率就很低(有些初學多執行緒編程的人,總喜歡用一個循環去檢查某個變數的值,這其實是一 種很嚴重的錯誤)。如果是使用通知的方式,效率則很高,因為非同步功能幾乎不需要做額外的操作。至於回調函數,其實和通知沒太多區別。 舉例: 1. concurrent.futures.ProcessPoolExecutor(3).submit(func,) 2. concurrent.futures.ThreadPoolExecutor(3).submit(func,)
阻塞
#阻塞調用是指調用結果返回之前,當前執行緒會被掛起(如遇到io操作)。函數只有在得到結果之後才會將阻塞的執行緒激活。有人也許會把阻塞調用和同步調用等同起來,實際上他是不同的。對於同步調用來說,很多時候當前執行緒還是激活的,只是從邏輯上當前函數沒有返回而已。 #舉例: #1. 同步調用:apply一個累計1億次的任務,該調用會一直等待,直到任務返回結果為止,但並未阻塞住(即便是被搶走cpu的執行許可權,那也是處於就緒態); #2. 阻塞調用:當socket工作在阻塞模式的時候,如果沒有數據的情況下調用recv函數,則當前執行緒就會被掛起,直到有數據為止。
非阻塞
#非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前也會立刻返回,同時該函數不會阻塞當前執行緒。
總結
1. 同步與非同步針對的是函數/任務的調用方式:同步就是當一個進程發起一個函數(任務)調用的時候,一直等到函數(任務)完成,而進程繼續處於激活狀態。而非同步情況下是當一個進程發起一個函數(任務)調用的時候,不會等函數返回,而是繼續往下執行當,函數返回的時候通過狀態、通知、事件等方式通知進程任務完成。 2. 阻塞與非阻塞針對的是進程或執行緒:阻塞是當請求不能滿足的時候就將進程掛起,而非阻塞則不會阻塞當前進程
三、並發編程之多執行緒
點我———————————–點我———————————–點我———————–
1、什麼是執行緒
執行緒顧名思義,就是一條流水線工作的過程,一條流水線必須屬於一個車間,一個車間的工作過程是一個進程
關係:
程式——>進程(至少一個主進程)——>執行緒(至少一個主執行緒,依賴於進程)
進程只是用來把資源集中到一起(進程只是一個資源單位,或者說資源集合),而執行緒才是cpu上的執行單位。


#可以想像成北京地鐵與上海地鐵是不同的進程,而北京地鐵里的13號線是一個執行緒,北京地鐵所有的線路共享北京地鐵所有的資源,比如所有的乘客可以被所有線路拉。
生活中進程、執行緒
2、創建執行緒的開銷小
如果我們的軟體是一個工廠,該工廠有多條流水線,流水線工作需要電源,電源只有一個即cpu(單核cpu)
一個車間就是一個進程,一個車間至少一條流水線(一個進程至少一個執行緒)
創建一個進程,就是創建一個車間(申請空間,在該空間內建至少一條流水線)
而建執行緒,就只是在一個車間內造一條流水線,無需申請空間,所以創建開銷小
3、執行緒與進程的區別
執行緒共享創建它的進程的地址空間 進程有自己的地址空間。
執行緒可以直接訪問進程的數據段 進程擁有父進程的數據段的自己的副本。
執行緒可以直接與進程的其他執行緒通訊 進程必須使用進程間通訊來與兄弟進程通訊。
新執行緒很容易創建 新進程需要複製父進程。
執行緒可以對同一進程的執行緒進行相當大的控制 進程只能對子進程進行控制。
對主執行緒的更改(取消、優先順序更改等)可能會影響進程中其他執行緒的行為 對父進程的更改不會影響子進程。
4、為何用多執行緒
多執行緒指的是,在一個進程中開啟多個執行緒
1. 多執行緒共享一個進程的地址空間 2. 執行緒比進程更輕量級,執行緒比進程更容易創建可撤銷,在許多作業系統中,創建一個執行緒比創建一個進程要快10-100倍,在有大量執行緒需要動態和快速修改時,這一特性很有用 3. 若多個執行緒都是cpu密集型的,那麼並不能獲得性能上的增強,但是如果存在大量的計算和大量的I/O處理,擁有多個執行緒允許這些活動彼此重疊運行,從而會加快程式執行的速度。