协程的原生挂起与恢复机制

目录

🔍 一、从开发者视角看协程挂起与恢复

🧠 二、协程挂起和恢复的机制原理:核心关键词

✅ 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.mzph.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 注册中心…