[TOC]
## 什么是進程和線程?
* **進程**是具有一定獨立功能的程序關于某個數據集合上的一次運行活動,**進程是系統進行資源分配和調度的一個獨立單位**
* **線程**是進程的一個實體,**是CPU調度和分派的基本單位**,它是比進程更小的能獨立運行的基本單位
## 進程和線程的關系是什么?
* 一個線程只能屬于一個進程,而一個進程可以有多個線程,但至少有一個線程。**線程是操作系統可識別的最小執行和調度單位**
* **資源分配給進程,同一進程的所有線程共享該進程的所有資源**。**同一進程中的多個線程共享代碼段(代碼和常量),數據段(全局變量和靜態變量),擴展段(堆存儲)**。但是每個線程擁有自己的棧段,棧段又叫運行時段,用來存放所有局部變量和臨時變量
* **處理機分給線程,即真正在處理機上運行的是線程**
* 線程在執行過程中,需要協作同步。**不同進程的線程間要利用消息通信的辦法實現同步**
## 進程與線程的區別是什么?
* 資源:進程是資源分配的基本單位,但線程不擁有資源,線程能訪問其所屬進程的資源;
* 調度:線程是獨立調度的基本單位,同一進程中線程的切換不會引起進程的切換,而不同進程間線程的切換會引起進程的切換;
* 系統開銷:進程的新建和撤銷時,系統需要為其分配和回收資源,如內存空間和I/O設備等,開銷遠大于線程的新建和撤銷。進程的切換需要當前進程CPU環境的保護和新進程環境的設置,而線程的切換只需要保存和設置少量的寄存器內容,開銷很小。因此,線程的系統開銷遠低于進程。
* 通信:線程可以直接讀寫進程數據進行通信,但進程需要IPC(進程間通信技術)進行通信(管道、消息隊列、共享內存)。
## 進程的狀態,各個狀態之間如何切換?
* 就緒:進程已處于準備好運行的狀態,即進程已分配到除CPU外的所有必要資源后,只要再獲得CPU,便可立即執行
* 執行:進程已經獲得CPU,程序正在執行狀態
* 阻塞:正在執行的進程由于發生某事件(如I/O請求、申請緩沖區失敗等)暫時無法繼續執行的狀態
## 怎么選擇多進程還是多線程?
? CPU密集型:偏重于計算,頻繁使用CPU,適合多進程。如機器學習。
? I/O密集型:經常輸入輸出,適合多線程。如爬蟲。
## 為什么進程上下文切換比線程上下文切換代價高?
進程切換分兩步:
* 切換頁目錄以使用新的地址空間
* 切換內核棧和硬件上下文
對于linux來說,線程和進程的最大區別就在于地址空間,對于線程切換,第1步是不需要做的,第2是進程和線程切換都要做的
切換的性能消耗:
* 線程上下文切換和進程上下問切換一個最主要的區別是線程的切換虛擬內存空間依然是相同的,但是進程切換是不同的。這兩種上下文切換的處理都是通過操作系統內核來完成的。內核的這種切換過程伴隨的最顯著的性能損耗是將寄存器中的內容切換出
* 另外一個隱藏的損耗是上下文的切換會擾亂處理器的緩存機制。簡單的說,一旦去切換上下文,處理器中所有已經緩存的內存地址一瞬間都作廢了。還有一個顯著的區別是當你改變虛擬內存空間的時候,處理的頁表緩沖(processor's Translation Lookaside Buffer (TLB))或者相當的神馬東西會被全部刷新,這將導致內存的訪問在一段時間內相當的低效。但是在線程的切換中,不會出現這個問題。
## 什么是進程(線程)同步?
首先需要明白廣義上的“同步”,所謂同步,即在一定條件下應當發生什么事件
如果只有一個進程,那么進程同步指的是這個進程每次運行時的過程是一樣的。而現在的操作系統在多道程序設計的背景下,進程基本上是異步的,即每次運行的過程都是不一樣的。但是結果可能是一樣的。
如果有兩個進程A和B(一般是協作關系),那么進程同步的意思是說,兩個進程的運行過程是相互制約的。相反,異步就是說兩個進程各走各的,不會考慮另一個進程的狀態。可想而知,兩個異步運行的進程如果是協作關系,那么很有可能出現不協調的情況(競爭條件的出現)。
兩個以上進程的同步與兩個進程的情況類似。
“進程”也可以換成線程,“互斥”只是為了實現進程同步而使用的一種手段。
## 進程同步的任務和原則是什么?
進程同步的主要任務:是對多個相關進程在執行次序上進行協調,以使并發執行的諸進程之間能有效地共享資源和相互合作,從而使程序的執行具有可再現性
同步機制遵循的原則:
* 空閑讓進;
* 忙則等待(保證對臨界區的互斥訪問);
* 有限等待(有限代表有限的時間,避免死等);
* 讓權等待,(當進程不能進入自己的臨界區時,應該釋放處理機,以免陷入忙等狀態)
## 協程是什么?
* 協程是微線程,在一個線程中執行,執行過程中可以隨時中斷,由用戶控制(進程和線程本質上是系統運行)。執行效率高,減少了線程切換和鎖開銷。
* 協程失去了標準線程使用多核的能力。**多進程+協程**,既可以利用多核,又能利用協程的高效率。
* 實現:asyncio(異步IO,即不用等待其結束就能進行其他操作),在yield處暫停等待指令。
## 協程相比線程的優勢是什么?
**協程執行效率高。**
* 協程由用戶控制,不需要線程切換開銷。與多線程相比,線程數量越多,協程的優勢越明顯;
* 協程不需要鎖機制。線程中需要用鎖保護數據,而協程不需要寫變量保護,只需要判斷狀態就好了。
## 進程、線程、協程的堆棧區別是什么?
* 進程:有獨立的堆棧,不共享堆也不共享棧;由操作系統調度;
* 線程:有獨立的棧,共享堆而不共享棧;由操作系統調度;
* 協程:有獨立的棧,共享堆而不共享棧;由程序員自己調度。
## 進程間通信的意義是什么?
數據傳輸:一個進程需要將它的數據發送給另一個進程;
資源共享:多個進程間共享同樣的資源;
通知事件:一個進程需要向另一個或一組進程發消息,通知它們發生了某種事件(如進程終止時要通知父進程)。
進程控制:有些進程希望完全控制另一個進程的執行(如Debug進程),此時控制進程希望能夠攔截另一個進程的所有陷入和異常,并能夠及時知道它的狀態改變。
## 進程間高級通信機制如何分類?
* 共享存儲器系統(存儲器中劃分的共享存儲區);實際操作中對應的是“剪貼板”(剪貼板實際上是系統維護管理的一塊內存區域)的通信方式,比如舉例如下:word進程按下ctrl+c,在ppt進程按下ctrl+v,即完成了word進程和ppt進程之間的通信,復制時將數據放入到剪貼板,粘貼時從剪貼板中取出數據,然后顯示在ppt窗口上。
* 消息傳遞系統(進程間的數據交換以消息(message)為單位,當今最流行的微內核操作系統中,微內核與服務器之間的通信,無一例外地都采用了消息傳遞機制。應用舉例:郵槽(MailSlot)是基于廣播通信體系設計出來的,它采用無連接的不可靠的數據傳輸。郵槽是一種單向通信機制,創建郵槽的服務器進程讀取數據,打開郵槽的客戶機進程寫入數據。
* 管道通信系統(管道即:連接讀寫進程以實現他們之間通信的共享文件(pipe文件,類似先進先出的隊列,由一個進程寫,另一進程讀))。實際操作中,管道分為:匿名管道、命名管道。匿名管道是一個未命名的、單向管道,通過父進程和一個子進程之間傳輸數據。匿名管道只能實現本地機器上兩個進程之間的通信,而不能實現跨網絡的通信。命名管道不僅可以在本機上實現兩個進程間的通信,還可以跨網絡實現兩個進程間的通信。
* **管道**:管道是單向的、先進先出的、無結構的、固定大小的字節流,它把一個進程的標準輸出和另一個進程的標準輸入連接在一起。寫進程在管道的尾端寫入數據,讀進程在管道的道端讀出數據。數據讀出后將從管道中移走,其它讀進程都不能再讀到這些數據。管道提供了簡單的流控制機制。進程試圖讀空管道時,在有數據寫入管道前,進程將一直阻塞。同樣地,管道已經滿時,進程再試圖寫管道,在其它進程從管道中移走數據之前,寫進程將一直阻塞。
* **信號量**:信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其它進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段
* **消息隊列**:是一個在系統內核中用來保存消 息的隊列,它在系統內核中是以消息鏈表的形式出現的。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩沖區大小受限等缺點
* **共享內存**:共享內存允許兩個或多個進程訪問同一個邏輯內存。**這一段內存可以被兩個或兩個以上的進程映射至自身的地址空間中**,一個進程寫入共享內存的信息,可以被其他使用這個共享內存的進程,通過一個簡單的內存讀取讀出,從而實現了進程間的通信\*\*。如果某個進程向共享內存寫入數據,所做的改動將立即影響到可以訪問同一段共享內存的任何其他進程。**共享內存是最快的IPC方式,它是針對其它進程間通信方式運行效率低而專門設計的。它往往與其它通信機制(如**信號量\*\*)配合使用,來實現進程間的同步和通信。
* **套接字**:套接字也是一種進程間通信機制,與其它通信機制不同的是,它可用于不同機器間的進程通信。
相關參考:[https://www.cnblogs.com/WindSun/p/11441090.html](https://www.cnblogs.com/WindSun/p/11441090.html)
## 進程的調度
**調度種類**
* **高級調度**:(High-Level Scheduling)又稱為作業調度,它決定把后備作業調入內存運行
* **低級調度**:(Low-Level Scheduling)又稱為進程調度,它決定把就緒隊列的某進程獲得CPU
* **中級調度**:(Intermediate-Level Scheduling)又稱為在虛擬存儲器中引入,在內、外存對換區進行進程對換
**非搶占式調度與搶占式調度**
* **非搶占式**:分派程序一旦把處理機分配給某進程后便讓它一直運行下去,直到進程完成或發生進程調度進程調度某事件而阻塞時,才把處理機分配給另一個進程
* **搶占式**:操作系統將正在運行的進程強行暫停,由調度程序將CPU分配給其他就緒進程的調度方式
**調度算法**
**FIFO或First Come, First Served (FCFS)先來先服務**
* 調度的順序就是任務到達就緒隊列的順序
* 公平、簡單(FIFO隊列)、非搶占、不適合交互式
* 未考慮任務特性,平均等待時間可以縮短
**Shortest Job First (SJF)**
* 最短的作業(CPU區間長度最小)最先調度
* SJF可以保證最小的平均等待時間
**Shortest Remaining Job First (SRJF)**
* SJF的可搶占版本,比SJF更有優勢
* SJF(SRJF): 如何知道下一CPU區間大小?根據歷史進行預測: 指數平均法
**優先權調度**
* 每個任務關聯一個優先權,調度優先權最高的任務
* 注意:優先權太低的任務一直就緒,得不到運行,出現“饑餓”現象
**Round-Robin(RR)輪轉調度算法**
* 設置一個時間片,按時間片來輪轉調度(“輪叫”算法)
* 優點: 定時有響應,等待時間較短;缺點: 上下文切換次數較多
* 時間片太大,響應時間太長;吞吐量變小,周轉時間變長;當時間片過長時,退化為FCFS
**多級隊列調度**
* 按照一定的規則建立多個進程隊列
* 不同的隊列有固定的優先級(高優先級有搶占權)
* 不同的隊列可以給不同的時間片和采用不同的調度方法
* 存在問題1:沒法區分I/O bound和CPU bound
* 存在問題2:也存在一定程度的“饑餓”現象
**多級反饋隊列**
* 在多級隊列的基礎上,任務可以在隊列之間移動,更細致的區分任務
* 可以根據“享用”CPU時間多少來移動隊列,阻止“饑餓”
* 最通用的調度算法,多數OS都使用該方法或其變形,如UNIX、Windows等
## 什么是共享內存,好處是什么?
共享內存可以說是最有用的進程間通信方式,也是最快的IPC形式。兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。由于多個進程共享同一塊內存區域,必然需要某種同步機制,互斥鎖和信號量都可以。
采用共享內存通信的一個顯而易見的好處是效率高,因為進程可以直接讀寫內存,而不需要任何數據的拷貝。對于像管道和消息隊列等通信方式,則需要在內核和用戶空間進行四次的數據拷貝,而共享內存則只拷貝兩次數據\[1\]:一次從輸入文件到共享內存區,另一次從共享內存區到輸出文件。實際上,進程之間在共享內存時,并不總是讀寫少量數據后就解除映射,有新的通信時,再重新建立共享內存區域。而是保持共享區域,直到通信完畢為止,這樣,數據內容一直保存在共享內存中,并沒有寫回文件。共享內存中的內容往往是在解除映射時才寫回文件的。因此,采用共享內存的通信方式效率是非常高的。
## 共享內存是怎么實現的?
> 簡單的說,共享內存是通過把同一塊內存分別映射到不同的進程空間中實現進程間通信。
而共享內存本身不帶任何互斥與同步機制。但當多個進程同時對同一內存進行讀寫操作時會破壞該內存的內容,所以,在實際中,同步與互斥機制需要用戶來完成。
## 共享內存的特點是什么?
(1)共享內存就是允許兩個不想關的進程訪問同一個內存
(2)共享內存是兩個正在運行的進程之間共享和傳遞數據的最有效的方式
(3)不同進程之間共享的內存通常安排為同一段物理內存
(4)共享內存不提供任何互斥和同步機制,一般用信號量對臨界資源進行保護。
(5)接口簡單
## 一個程序從開始運行到結束的完整過程(四個過程)是什么?
預處理:條件編譯,頭文件包含,宏替換的處理,生成.i文件。
編譯:將預處理后的文件轉換成匯編語言,生成.s文件
匯編:匯編變為目標代碼(機器代碼)生成.o的文件
鏈接:連接目標代碼,生成可執行程序
- Go準備工作
- 依賴管理
- Go基礎
- 1、變量和常量
- 2、基本數據類型
- 3、運算符
- 4、流程控制
- 5、數組
- 數組聲明和初始化
- 遍歷
- 數組是值類型
- 6、切片
- 定義
- slice其他內容
- 7、map
- 8、函數
- 函數基礎
- 函數進階
- 9、指針
- 10、結構體
- 類型別名和自定義類型
- 結構體
- 11、接口
- 12、反射
- 13、并發
- 14、網絡編程
- 15、單元測試
- Go常用庫/包
- Context
- time
- strings/strconv
- file
- http
- Go常用第三方包
- Go優化
- Go問題排查
- Go框架
- 基礎知識點的思考
- 面試題
- 八股文
- 操作系統
- 整理一份資料
- interface
- array
- slice
- map
- MUTEX
- RWMUTEX
- Channel
- waitGroup
- context
- reflect
- gc
- GMP和CSP
- Select
- Docker
- 基本命令
- dockerfile
- docker-compose
- rpc和grpc
- consul和etcd
- ETCD
- consul
- gin
- 一些小點
- 樹
- K8s
- ES
- pprof
- mycat
- nginx
- 整理后的面試題
- 基礎
- Map
- Chan
- GC
- GMP
- 并發
- 內存
- 算法
- docker