協程的原生掛起與恢復機制

目錄

🔍 一、從開發者視角看協程掛起與恢復

🧠 二、協程掛起和恢復的機制原理:核心關鍵詞

? suspend 函數 ≠ 普通函數

? Continuation(協程的控制器)

🔧 三、編譯器做了什么?(狀態機原理)

🧵 四、線程沒被阻塞?那協程在哪里“等”?

📦 五、Kotlin 標準庫中協程的核心類有哪些?

💡 六、協程掛起和恢復流程圖解(簡化):

? 七、真實編譯代碼示例(有點硬核)

🧘 八、總結:Kotlin 原生掛起/恢復的核心點

下面我們模擬 Kotlin 協程的掛起與恢復機制,也就是一個 suspend 函數在底層是如何通過 Continuation 實現掛起和恢復的。我們會用純 Kotlin 實現一個簡單的“協程執行流程”,不依賴 kotlinx.coroutines。

🎯 目標

🛠 模擬版:協程掛起 + 恢復(純 Kotlin)

🧠 稍作說明:

? 輸出效果如下:

💡 總結


🔍 一、從開發者視角看協程掛起與恢復

我們先看一個很簡單的協程示例:

suspend fun fetchUser(): User {delay(1000)  // 掛起1秒(非阻塞)return User("Alice")
}fun main() = runBlocking {val user = fetchUser()println(user.name)
}

這個 fetchUser() 函數 看起來像同步函數,但實際上內部的 delay()非阻塞的掛起函數
所以問題來了:

? Kotlin 是如何“掛起”這個函數,并在一秒后“恢復”它的?


🧠 二、協程掛起和恢復的機制原理:核心關鍵詞

? suspend 函數 ≠ 普通函數

suspend 函數不是魔法,它被 Kotlin 編譯器轉換成 狀態機 + 回調對象。

? Continuation(協程的控制器)

Kotlin 協程的底層就是使用一個叫 Continuation<T> 的對象來保存“執行點”。

你可以簡單理解為:

interface Continuation<T> {val context: CoroutineContextfun resumeWith(result: Result<T>)
}

這個 resumeWith 方法,就是協程恢復的“入口”。


🔧 三、編譯器做了什么?(狀態機原理)

當你寫下如下代碼時:

suspend fun test() {val a = getValue1()val b = getValue2(a)println(b)
}

Kotlin 編譯器會將其“翻譯”為一個類似下面的 狀態機結構

class TestCoroutine(val continuation: Continuation<Unit>) : Continuation<Unit> {var state = 0var result: Any? = nullfun resume(value: Any?) {result = valuewhen (state) {0 -> {state = 1getValue1(this)  // 掛起點}1 -> {val a = resultstate = 2getValue2(a, this)  // 第二個掛起點}2 -> {val b = resultprintln(b)continuation.resumeWith(Result.success(Unit))}}}
}

所以,Kotlin 協程的“掛起函數”,在底層實際上是一個 狀態轉換器(狀態機),每次調用 resume() 進入下一個狀態繼續執行。


🧵 四、線程沒被阻塞?那協程在哪里“等”?

Kotlin 協程并不是占用線程的,它 將函數“暫停”,并注冊回調,當事件完成后再“恢復”。

比如:

delay(1000)

并不是在當前線程中 sleep 1 秒,而是:

  1. delay() 會發起一個定時器(使用調度器 Dispatcher)

  2. 當前協程從調用棧“退出”,線程繼續干別的事情

  3. 一秒后,定時器觸發回調,調度器調用之前保存的 Continuation.resume(),繼續執行協程邏輯

? 所以:線程是空出來的!不會阻塞! 這就是協程相比線程的最大優勢。


📦 五、Kotlin 標準庫中協程的核心類有哪些?

類名作用
Continuation<T>保存協程當前狀態與恢復函數
CoroutineContext包含調度器、異常處理器等上下文
CoroutineDispatcher指定協程在哪個線程或線程池執行
SuspendFunction被編譯為 Continuation 形式的函數
CancellableContinuation支持取消、超時的 continuation 封裝

💡 六、協程掛起和恢復流程圖解(簡化):

協程開始執行↓遇到掛起點(suspend)↓保存狀態(Continuation)↓退出當前線程(不阻塞)↓等待外部事件完成(如定時、網絡響應)↓調度器觸發回調(如 resumeWith)↓讀取 Continuation,恢復執行

?


? 七、真實編譯代碼示例(有點硬核)

suspend fun foo(): Int {return 1
}

編譯器實際會生成一個這樣的函數簽名(偽代碼):?

fun foo(continuation: Continuation<Int>): Any {return 1
}

?

所以 suspend 函數其實是個 帶 continuation 參數的函數


🧘 八、總結:Kotlin 原生掛起/恢復的核心點

說明
? 編譯器轉為狀態機每個掛起點變成一個狀態標簽
? 掛起函數不阻塞線程線程空出來,提高性能
? Continuation 保存狀態可以在任意掛起點恢復
? 自動恢復執行協程調度器控制何時 resume
? 語法“像同步”但內部是異步寫法優雅、性能優越

下面我們模擬 Kotlin 協程的掛起與恢復機制,也就是一個 suspend 函數在底層是如何通過 Continuation 實現掛起和恢復的。我們會用純 Kotlin 實現一個簡單的“協程執行流程”,不依賴 kotlinx.coroutines


🎯 目標

模擬這個掛起函數的運行邏輯:

suspend fun testSuspend(): String {println("開始")delayFake(1000)println("恢復后")return "完成"
}

我們來用“非 suspend 函數”手動模擬整個過程👇


🛠 模擬版:協程掛起 + 恢復(純 Kotlin)

interface Continuation<T> {fun resumeWith(result: T)
}// 模擬 delay 函數(異步延遲執行 resume)
fun delayFake(timeMillis: Long, continuation: Continuation<Unit>) {println("掛起,$timeMillis ms 后恢復")Thread {Thread.sleep(timeMillis)continuation.resumeWith(Unit) // 模擬恢復協程}.start()
}// 實現狀態機類
class MyCoroutine : Continuation<Unit> {var state = 0 // 0=起始狀態,1=恢復狀態fun start() {resumeWith(Unit) // 初始調用}override fun resumeWith(result: Unit) {when (state) {0 -> {println("開始")state = 1delayFake(1000, this) // 傳入當前 continuation}1 -> {println("恢復后")println("完成")}}}
}fun main() {MyCoroutine().start()// 主線程不能立即退出Thread.sleep(2000)
}

🧠 稍作說明:

部分含義
Continuation模擬協程控制器
delayFake模擬異步掛起點(非阻塞)
state當前執行狀態,相當于編譯器生成的狀態機標簽
resumeWith通過判斷 state 來恢復執行

? 輸出效果如下:

開始
掛起,1000 ms 后恢復
恢復后
完成

你可以看到,雖然我們在 delayFake() 里“暫停”了協程邏輯,但線程沒有阻塞,我們手動模擬了協程掛起點恢復后的執行。


💡 總結

這個例子展示了 Kotlin 協程在底層是如何通過:

  • Continuation 保存協程的執行點

  • 狀態變量管理協程的控制流程

  • 回調觸發恢復邏輯

來實現“掛起”與“恢復”的機制。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/76772.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/76772.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/76772.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c++11--std::forwaord--完美轉發

std::forword的作用 完美轉發的核心目的是保持參數的原始類型&#xff08;包括const/volatile限定符和左值/右值性質&#xff09;不變地傳遞給其他函數。 為什么需要完美轉發 在沒有完美轉發之前&#xff0c;我們面臨以下問題&#xff1a; 模板參數傳遞中的值類別丟失 當參數…

Linux安裝開源版MQTT Broker——EMQX服務器環境從零到一的詳細搭建教程

零、EMQX各個版本的區別 EMQX各個版本的功能對比詳情https://docs.emqx.com/zh/emqx/latest/getting-started/feature-comparison.html

計算機組成原理-存儲器

1. 存儲器的定義與作用 存儲器是計算機系統中用于存儲程序、數據和中間結果的硬件設備&#xff0c;是計算機五大核心部件之一。 核心功能&#xff1a; 提供數據的 臨時或永久存儲 能力。支持CPU按需快速存取指令和數據&#xff0c;是程序運行的物理基礎。 2. 存儲器的分類 …

單片機領域中哈希表

以下是單片機領域中哈希表的實際應用及編程實例&#xff1a; 1.哈希表在單片機中的實際應用場景 ? 命令解析&#xff1a;在單片機通信中&#xff0c;經常需要解析接收到的命令。使用哈希表可以快速地將命令字符串映射到對應的處理函數&#xff0c;提高命令解析的效率。 ? 數…

算法思想之位運算(一)

歡迎拜訪&#xff1a;霧里看山-CSDN博客 本篇主題&#xff1a;算法思想之位運算(一) 發布時間&#xff1a;2025.4.12 隸屬專欄&#xff1a;算法 目錄 滑動窗口算法介紹六大基礎位運算符常用模板總結 例題位1的個數題目鏈接題目描述算法思路代碼實現 比特位計數題目鏈接題目描述…

封裝Tcp Socket

封裝Tcp Socket 0. 前言1. Socket.hpp2. 簡單的使用介紹 0. 前言 本文中用到的Log.hpp在筆者的歷史文章中都有涉及&#xff0c;這里就不再粘貼源碼了&#xff0c;學習地址如下&#xff1a;https://blog.csdn.net/weixin_73870552/article/details/145434855?spm1001.2014.3001…

全星APQP軟件:為用戶提供高效、合規、便捷的研發管理體驗

全星APQP軟件&#xff1a;為用戶提供高效、合規、便捷的研發管理體驗 為什么選擇全星APQP軟件系統&#xff1f; 在汽車及高端制造行業&#xff0c;研發項目管理涉及APQP&#xff08;先期產品質量策劃&#xff09;、FMEA&#xff08;失效模式與影響分析&#xff09;、CP&#x…

CTF--網站被黑

一、原題&#xff1a; &#xff08;1&#xff09;提示&#xff1a;網站被黑了 黑客會不會留下后門 &#xff08;2&#xff09;原網頁&#xff1a; 二、步驟&#xff1a; 1.在終端掃描網址&#xff1a; 2.掃描后發現&#xff1a;shell.php 3.輸入網址&#xff1a;http://117.…

入門到精通,C語言十大經典程序

以下是十個經典的C語言程序示例&#xff0c;這些程序涵蓋了從基礎到稍復雜的應用場景&#xff0c;適合初學者和有一定基礎的開發者學習和參考。 1. Hello, World! 這是每個初學者學習編程時的第一個程序&#xff0c;用于驗證開發環境是否正確配置。 #include <stdio.h>…

神經網絡入門—自定義神經網絡續集

修改網絡 神經網絡入門—自定義網絡-CSDN博客 修改數據集&#xff0c;yx^2 # 生成一些示例數據 x_train torch.tensor([[1.0], [2.0], [3.0], [4.0]], dtypetorch.float32) y_train torch.tensor([[1.0], [4.0], [9.0], [16.0]], dtypetorch.float32) 將預測代碼改為&…

【browser-use+deepseek】實現簡單的web-ui自動化

browser-use Web-UI 一、browser-use是什么 Browser Use 是一款開源Python庫&#xff0c;專為大語言模型設計的智能瀏覽器工具&#xff0c;目的是讓 AI 能夠像人類一樣自然地瀏覽和操作網頁。它支持多標簽頁管理、視覺識別、內容提取&#xff0c;并能記錄和重復執行特定動作。…

Vue--常用組件解析

綁定事件v-on和按鍵修飾符 v-on:click 表示在button元素上監聽click事件 簡寫&#xff1a;click enter space tab 按鍵修飾符 keyup是用戶松開按鍵才觸發 keydown是在用戶按下按鍵時立即觸發 代碼展示&#xff1a; <!DOCTYPE html><html lang"en" xml…

《JVM考古現場(十八):造化玉碟·用字節碼重寫因果律的九種方法》

"鴻蒙初判&#xff01;當前因果鏈突破十一維屏障——全體碼農修士注意&#xff0c;《JVM考古現場&#xff08;十八&#xff09;》即將渡劫飛升&#xff01;" 目錄 上卷陰陽交纏 第一章&#xff1a;混沌初開——JVM因果律的量子糾纏 第二章&#xff1a;誅仙劍陣改—…

前端vue 項目px轉為rem的自適應解決方案

postcss-pxtorem&#xff08;或是postcss-px2rem&#xff09; npm install postcss-pxtorem amfe-flexible --save-dev 在入口文件 main.js 中引入 amfe-flexible&#xff08;響應式適配&#xff09;&#xff1a; main.js import amfe-flexible // 自動設置 html 的 font-s…

基于時間序列分解與XGBoost的交通通行時間預測方法解析

一、問題背景與數據概覽 在城市交通管理系統中,準確預測道路通行時間對于智能交通調度和路徑規劃具有重要意義。本文基于真實道路傳感器數據,構建了一個結合時間序列分解與機器學習模型的預測框架。數據源包含三個核心部分: 道路通行數據(new_gy_contest_traveltime_train…

Day14:關于MySQL的索引——創、查、刪

前言&#xff1a;先創建一個練習的數據庫和數據 1.創建數據庫并創建數據表的基本結構 -- 創建練習數據庫 CREATE DATABASE index_practice; USE index_practice;-- 創建基礎表&#xff08;包含CREATE TABLE時創建索引&#xff09; CREATE TABLE products (id INT PRIMARY KEY…

【C++】繼承:萬字總結

&#x1f4dd;前言&#xff1a; 這篇文章我們來講講面向對象三大特性之一——繼承 &#x1f3ac;個人簡介&#xff1a;努力學習ing &#x1f4cb;個人專欄&#xff1a;C學習筆記 &#x1f380;CSDN主頁 愚潤求學 &#x1f304;其他專欄&#xff1a;C語言入門基礎&#xff0c;py…

Java 架構設計:從單體架構到微服務的轉型之路

Java 架構設計&#xff1a;從單體架構到微服務的轉型之路 在現代軟件開發中&#xff0c;架構設計的選擇對系統的可擴展性、可維護性和性能有著深遠的影響。隨著業務需求的日益復雜和用戶規模的不斷增長&#xff0c;傳統的單體架構逐漸暴露出其局限性&#xff0c;而微服務架構作…

Django3 - 開啟Django Hello World

一、開啟Django Hello World 要學習Django首先需要了解Django的操作指令&#xff0c;了解了每個指令的作用&#xff0c;才能在MyDjango項目里編寫Hello World網頁&#xff0c;然后通過該網頁我們可以簡單了解Django的開發過程。 1.1 Django的操作指令 無論是創建項目還是創建項…

2025阿里云AI 應用-AI Agent 開發新范式-MCP最佳實踐-78頁.pptx

2025阿里云AI 應用-AI Agent 開發新范式-MCP最佳實踐&#xff0c;包含以下內容&#xff1a; 1、AI 應用架構新范式 2、云原生API網關介紹 3、云原生API網關底座核心優勢 4、流量網關最佳實踐 5、AI 網關代理 LLM 最佳實踐 6、MCP網關最佳實踐 7、MSE Nacos MCP Server 注冊中心…