您現在的位置是:首頁 > 遊戲

面試官:什麼是程序、執行緒、協程?

由 架構師半仙 發表于 遊戲2021-09-16
簡介在同一個程序中,一個執行緒執行完一個時間片後,作業系統核心透過硬體的計數器中斷處理器,讓執行緒強制暫停,將該執行緒的暫存器存入記憶體,等待下次排程

cpu掉執行緒是什麼意思

在面試中,經常會問到程序、執行緒、協程的問題。本節主要講解程序、執行緒、協程的概念和之間的聯絡。

1。程序

程序是一種抽象的概念,沒有統一的標準定義。程序是作業系統分配資源最小單位,程序使用獨立的資料空間,由程式,資料和程式控制塊三部分組成,程序之間的記憶體是相互隔離的,是具有獨立功能的程式一次動態執行的過程。

程式,是控制程序的指令集。

資料,程序執行時所需要的資料和工作區。

程式控制塊(Program Control Block,簡稱PCB),包含程序的描述資訊和控制資訊,是程序存在的唯一標誌。

同樣程序間也是可以通訊(IPC)的,透過管道(Pipe)、命名管道(FIFO)、訊息佇列(Message Queue) 、訊號量(Semaphore) 、共享記憶體(Shared Memory)、套接字(Socket)等方式進行通訊。同樣程序擁有自己的狀態,這個不是本課程的重點,不做詳細講解。

大名鼎鼎的反向代理工具Nginx,實現高併發除了採用多路複用IO,還有透過多程序,而不是透過多執行緒,由於程序間記憶體都是獨立的,所以不用擔心併發問題。每個節點有一個master程序,fork出多個worker子程序,master程序負責管理,把指令傳遞給worker程序處理。worker程序數一般是cpu的核數。

2。執行緒

執行緒是處理器排程和分派的基本單位,是程式執行的最小單位,執行緒共享程序的資料空間,由執行緒ID、當前指令指標PC、暫存器和堆疊組成。程序中包含一個和多個執行緒,程序中執行緒記憶體是可見的,不同程序間的執行緒記憶體不可見。

2。1 任務排程

大部分作業系統的任務排程是採用時間片輪轉的搶佔式排程方式。那麼什麼是CPU時間片呢?

CPU時間片是分配給執行緒的執行時間,Linux一般是5~800ms,Windows一般20ms。

在同一個程序中,一個執行緒執行完一個時間片後,作業系統核心透過硬體的計數器中斷處理器,讓執行緒強制暫停,將該執行緒的暫存器存入記憶體,等待下次排程。

同理,下個執行緒怎麼開始執行呢?作業系統核心透過檢視執行緒列表決定執行哪個執行緒,從記憶體中恢復該執行緒的暫存器,恢復執行。這樣就完成了執行緒的輪流執行。

執行緒和程序類似,也有自己的狀態,正在執行的執行緒叫執行狀態,暫停執行的叫做就緒狀態。

CPU透過時間片分配演算法不斷的迴圈任務,每次執行緒切換都會伴隨著一次執行緒上下文切換。執行緒上下文切換包含哪些操作呢?首先,切換前會儲存上個執行緒的任務狀態,便於下次切換會該執行緒,然後加在新的執行緒狀態。這樣執行緒從儲存到再載入的過程就是一次上下文切換。

好比程式設計師寫程式碼,從一個分支切換到另外一個分支,需要check in上一個分支的程式碼,然後check out新分支的程式碼。

執行緒上下文切換的代價很大,應該儘量避免。

3。協程

程序是重量級的物件,後來發明了執行緒,資源開銷更小。但是執行緒也是一個重量級的物件,頻繁的建立和、銷燬、上下文切換成本都很高。

目前解決方案是協程(Coroutine),也被稱為輕量級的執行緒。協程相比執行緒有如下區別:

佔用記憶體大小不同。執行緒預設的stack一般是1M,協程一般是1k。

排程者不同。執行緒是透過作業系統排程,是核心態。協程是使用者自己排程,是使用者態,減少上下文切換,提高了效率。

協程是執行在同一個執行緒上,避免了競爭關係而使用鎖。

很多開發語言都支援協程,比如Golang、Python、Lua、Kotlin等。很遺憾,Java不支援,Java有支援協程的框架實現,比如quasar和kotlin。

3。1 協程的應用場景

作業系統並不知道協程的存在,協程只是使用者態的任務。

現在我們有促銷的場景,假如有10000個請求過來,我們為每個請求建立一個執行緒去執行,包括查詢扣庫存、扣款等,假如每個執行緒佔用4M大小,10000執行緒就是39G的記憶體。在執行的過程中,CPU透過時間片分配演算法,使執行緒不斷的切換。出現了兩個問題,一是執行緒的佔用非常多的記憶體,二是執行緒上下文切換佔用了大量的系統時間。

現在有了協程,剛好解決以上兩個問題。協程執行線上程上,一個協程執行完畢後,主動讓出,讓另一個協程去執行。避免了建立大量的執行緒和頻繁的執行緒上下文切換。

協程並沒有增加執行緒數量,只是在執行緒的基礎之上透過分時複用的方式執行多個協程

,而且協程的切換在使用者態完成,切換的代價比執行緒從使用者態到核心態的代價小很多。

那麼什麼場景不適合協程呢?

1。容易導致執行緒阻塞的操作。協程是執行線上程上,作業系統不知道協程的存在,當執行緒阻塞時,協程同樣阻塞不能執行。比如阻塞IO。同理,協程適合非同步IO。

2。協程不適合計算密集型的任務,計算密集型的任務本身不需要大量的執行緒切換,因此協程的作用也十分有限,反而還增加了協程切換的開銷。

總結:

從重量級上依次從大到小,程序 > 執行緒 > 管程。

程序中包含多個執行緒,管程是執行線上程中。

程序是作業系統資源分配的最小單位,執行緒是CPU排程的基本單位。

執行緒建立、銷燬、上下文切換的代價很大,可以用管程的方案解決。

協程屬於使用者態,作業系統並不知道協程的存在。

協程不適合容易導致執行緒阻塞的任務和計算密集型任務,比如阻塞IO,比如非同步IO,才能發揮很大的作用。

推薦文章