摘要:也就是現代操作系統的虛擬內存空間。有在兩個進程之間切換狀態的時候,需要把內存的映射關系調整過來,否則虛擬內存的地址是無法對應到正確的物理地址的。但是原理是非常類似的。協程與線程的區別在于,協程的是在完全在用戶態,由語言的或者是庫來完成的。
TL;DR
筆者最美好的記憶來自于早年在6502 cpu的cc800上寫匯編的年代, 那個時代的計算機甚至沒有操作系統,也沒有實模式等保護機制。在6502上寫匯編應用其實非常簡單,系統會把bin文件加載到一個固定的內存地址中,cpu會固定地從一個特定的位置開始執行。然后cpu就按照你提供的機器指令開始一條一條的執行。在高級語言中的“函數調用”的概念,在匯編里主要體現為兩個寄存器。寄存器是cpu內部臨時保存數據的區域,相當于高級語言里的變量。但是有一個寄存器是特殊的,它存放了cpu當前正在執行的指令的內存地址(Instruction Register)。一個高級語言中的函數一般會被編譯成指令存放在一段連續的內存空間中(data segment)。那么所謂函數執行到了第幾行這樣的信息其實就是保存在這個Instruction Register中的。另外一個很特殊的寄存器是Stack Register,它其中存放的內存地址指向的內存區域用于函數之間傳遞參數和返回值,以及存放一個函數內的局部變量。如果不考慮現代計算機cpu中各種各樣其他存放中間結果的寄存器,理論上保存了Instruction Register(執行到哪兒了)和Stack Register(堆棧上的變量)就保存了一個函數的當前執行狀態,分別是函數當前執行到了哪,以及這個函數局部變量所代表的當前state。
事實上,操作系統的幾個關鍵切換也是這么來完成的。操作系統提供了兩個執行態,一個是用戶態,一般我們的代碼都是執行在用戶態的。另外一個是內核態,像驅動程序之類的代碼會用各種方式被加載到操作系統內部執行在內核之中。內核態里的代碼可以完全控制CPU的I/O中斷,從而可以和外部設備交互。用戶態的代碼屬于受限代碼,必須把I/O請求通過syscall交由運行在內核態的操作系統來完成。當一個cpu的核在執行用戶態代碼時,其寄存器里存放的狀態是你的應用的代碼的狀態,但是應用要進行I/O操作的時候,cpu要被切換到內核的代碼里去執行內核態的代碼。這里就需要進行一次context switch,所謂context switch其實原理不會比把寄存器的值存到內存的一個地方,等回來的時候再把內存中臨時保存的值加載回寄存器復雜多少。
操作系統還有一個需要進行context switch的地方,那就是在協程與協程之間。操作系統在執行一個ELF或者PE的可執行文件的時候,對于這個可執行文件內的匯編代碼來說,整個內存尋址空間是獨立的。也就是1.exe的執行狀態完全無法感知到2.exe的執行狀態的內存。也就是現代操作系統的虛擬內存空間。有cpu在兩個進程之間切換狀態的時候,需要把內存的映射關系調整過來,否則虛擬內存的地址是無法對應到正確的物理地址的。一個進程內的兩個線成切換的時候,要稍微簡單一些,只需要把當前線成正在執行的位置和棧做切換就可以了。
無論是操作系統做user/kernel的switch,還是process/process,thread/thread的switch,其實現方式都是大同小異的。通過把“當前執行狀態”這樣的一個抽象概念落實為一個具體的數據結構存儲起來,然后指揮cpu在不同的場合加載不同的數據恢復不同的“當前執行狀態”。
在高級語言中,一個函數正在執行的位置以及其狀態,內部都可以有一個抽象的表達方式。有的高級語言直接被編譯成原生的機器碼,那么其執行狀態的表述就和操作系統的context switch的context非常類似。有的高級語言自身執行在一個虛擬機之上,那么其context的表述可能是虛擬機的instruction register和stack register,而不是80x86這樣原生的機器的物理寄存器。但是原理是非常類似的。
取決于語言設計者的覺悟,有的語言會把這種表達執行狀態的能力直接提供出來,讓一個函數在執行過程中可以把當前狀態保存,然后把執行權交給另外一個函數執行,等那個函數放棄執行權回來的時候再把保存的狀態恢復。這也就是所謂的協程(co-routine)。協程與線程的區別在于,協程的context switch是在完全在用戶態,由語言的runtime或者是庫來完成的。而線程的context switch則是操作系統來完成的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/45309.html
摘要:協程協程就是用戶態的線程要理解是什么是用戶態的線程,必然就要先理解什么是內核態的線程。記住,不是協程,而是協程需要借助的特性來實現。 協程 協程就是用戶態的線程 要理解是什么是用戶態的線程,必然就要先理解什么是內核態的線程。 內核態的線程是由操作系統來進行調度的,在切換線程上下文時,要先保存上一個線程的上下文,然后執行下一個線程,當條件滿足時,切換回上一個線程,并恢復上下文。 協程也...
摘要:它避免了上下文切換的額外耗費,兼顧了多線程的優點,簡化了高并發程序的復雜。而可以理解為一種語言的協程。線程輕量級進程,,是程序執行流的最小單元。一個標準的線程由線程,當前指令指針,寄存器集合和堆棧組成。其實就是或者等語言中的多線程開發。 grape 全部視頻:https://segmentfault.com/a/11... 原視頻地址:https://biglive.xueersi.c...
摘要:如果僅依靠程序自動交出控制的話,那么一些惡意程序將會很容易占用全部時間而不與其他任務共享。多個操作可以在重疊的時間段內進行。 PHP下的異步嘗試系列 如果你還不太了解PHP下的生成器,你可以根據下面目錄翻閱 PHP下的異步嘗試一:初識生成器 PHP下的異步嘗試二:初識協程 PHP下的異步嘗試三:協程的PHP版thunkify自動執行器 PHP下的異步嘗試四:PHP版的Promise ...
摘要:經過半年的沉淀,加上對,和分布式這塊的補齊,終于開始重拾面試信心,再次出征。面試官提示沒有提到線程的有內核態的切換,程只在用戶態調度。三面綜合技術面這面面的是陣腳大亂,面試官采用刨根問底的方式提問,終究是面試經驗不夠,導致面試的節奏有點亂。 經過半年的沉淀,加上對MySQL,redis和分布式這塊的補齊,終于開始重拾面試信心,再次出征。 鵝廠 面試職位:go后端開發工程師,接受從Jav...
閱讀 2353·2021-11-16 11:52
閱讀 2332·2021-11-11 16:55
閱讀 758·2021-09-02 15:41
閱讀 2989·2019-08-30 15:54
閱讀 3148·2019-08-30 15:54
閱讀 2257·2019-08-29 15:39
閱讀 1515·2019-08-29 15:18
閱讀 977·2019-08-29 13:00