七、並發編程(進程與線程)

  • 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處理,擁有多個線程允許這些活動彼此重疊運行,從而會加快程序執行的速度。

很形象的線程小故事