当前位置: 首页 > news >正文

线程与协程

1. 线程与协程

1.1. “函数调用级别”的切换、上下文切换

1. 函数调用级别的切换

“函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。

举例说明:

当你在程序中写一个函数调用:

funcA()

然后 funcA 执行完后返回,CPU 不需要保存太多额外的信息,只是:

  • 压栈/出栈(保存调用点、局部变量等)
  • 跳转指令地址(比如函数返回到调用者)

这种切换就是非常轻量级的,发生在用户态,速度快、成本低。

协程之间的切换通常只涉及「函数调用级别」的保存和恢复,例如程序计数器(PC)、栈指针(SP)等。

 

2. 上下文切换

上下文切换是操作系统在多任务之间切换时保存和恢复执行状态的过程,通常发生在线程/进程之间。

典型上下文包含:

  • CPU 寄存器(程序计数器 PC、堆栈指针 SP、通用寄存器)
  • 内存映射 / 虚拟地址空间(尤其是进程间)
  • 线程/进程控制块(如 PCB/TCB)

上下文切换的代价大:

  1. 保存当前线程的寄存器、状态
  2. 切换到内核态(Trap)
  3. 操作系统调度另一个线程/进程
  4. 恢复新线程的上下文
  5. 切换回用户态,继续执行

这会消耗 CPU 时间、内存带宽和系统资源,频繁切换会严重影响性能。

对比总结

项目

协程切换(函数调用级别)

线程/进程切换(上下文切换)

切换方式

用户态,像调用函数一样

操作系统调度,涉及内核态

状态保存/恢复

少量(程序计数器、栈指针)

全部寄存器、堆栈、内存映射等

是否切内核态

是(陷入内核)

开销

极小

较大(系统调用 + 状态切换)

性能影响

轻微

明显(频繁切换容易降低性能)

1.2. 线程(Thread)

概念:

线程是操作系统调度的最小单位,一个线程对应一条执行路径。多个线程可以并发执行任务,从而提升程序的响应性和性能。

特点:

  • 每个线程有自己的堆栈空间和程序计数器
  • 多个线程共享进程内的资源(如内存、文件);
  • 线程之间切换需要操作系统调度,代价较高(上下文切换)
  • 在多核 CPU 下,线程可以实现真正的并行(每核跑一个线程);
  • 适合 I/O 密集和 CPU 密集场景,但创建和调度较重。

举例(Python 中):

import threadingdef task():print("线程正在运行")t = threading.Thread(target=task)
t.start()

1.3. 协程(Coroutine)

概念:

协程是一种用户态的轻量级线程,又叫微线程,不由操作系统调度,而是由程序自己控制何时挂起、何时恢复

特点:

  • 本质是单线程内的并发;
  • 用于I/O 密集型任务非常高效(如网络请求、文件读写);
  • 切换开销小,不需要线程上下文切换;
  • 依靠语言或框架调度(如 Python 的 asyncio、Go 的 goroutine);
  • 不适合 CPU 密集任务(因为不能并行运算)。

举例(Python asyncio):

import asyncioasync def task():print("协程正在运行")await asyncio.sleep(1)print("协程运行结束")asyncio.run(task())

1.4. 线程 vs 协程对比总结

对比点

线程(Thread)

协程(Coroutine)

调度方式

操作系统调度

程序主动让出控制权(如 await

是否并发/并行

可实现并发,也可在多核并行

仅并发,不并行(除非多线程协程)

切换开销

大(上下文切换、内核态)

小(用户态)

编程复杂度

中等(注意锁、共享数据)

简单(适合异步 I/O)

适用场景

CPU 密集、I/O 密集

高并发 I/O 密集(如爬虫、Web服务)

Python 举例

threading模块

asyncio, trio, FastAPI

 

什么时候选线程?什么时候选协程?

场景

推荐使用

理由

文件读写、数据库操作

协程(asyncio)

I/O 密集、无需上下文切换、轻量高效

网络服务(如爬虫、Web)

协程(asyncio)

可处理成千上万连接,资源开销低

CPU 密集型计算

多线程 / 多进程

协程无优势,应考虑并行处理能力

简单并发

线程即可

写法直观,不涉及复杂 async/await

 

http://www.xdnf.cn/news/966583.html

相关文章:

  • Prometheus + Grafana 监控 RabbitMQ 实践指南
  • Spring Boot 分层架构与数据流转详解
  • Word中如何对文献应用的格式数字连起来,如:【1-3】
  • 如何看容器的ip地址
  • 每日收获总结20250610
  • 循环结构使用
  • Java 通用实体验证框架:从业务需求到工程化实践【生产级 - 适用于订单合并前置校验】
  • B2B供应链交易平台多商户电商商城系统开发批发采购销售有哪些功能?发展现状如何?
  • 什么是库存周转?如何用进销存系统提高库存周转率?
  • 第五章 GPIO示例
  • PennyLane 是一个用于量子计算、量子机器学习和量子化学的跨平台 Python 库。由研究人员构建,用于研究
  • 向量数据库ChromaDB的使用
  • Vim 复制/剪切/粘贴命令完整学习笔记
  • java Condition类
  • Alerting中配置多个OpsGenie时,如何匹配同一个条件匹配多个opsgenie的contact points
  • 【WiFi帧结构】
  • python/java环境配置
  • Django的HelloWorld程序
  • 1.4 超级终端
  • vue3 hooks的结构和作用和具体场景例子
  • 业财融合怎么做?如何把握业务与财务的边界?
  • @Configuration原理与实战
  • 【Kafka】消息队列Kafka知识总结
  • iview组件库:关于分页组件的使用与注意点
  • 什么是数据转换?数据转换有哪些方式?
  • 2025年06月10日Github流行趋势
  • Java SE - 数组
  • A 找倍数 (线段树)
  • 凤凰双展翅之七七一五八九五隔位六二五
  • LeetCode 146.LRU缓存