0

0

c# 什么是线程上下文切换 它的开销有多大

幻夢星雲

幻夢星雲

发布时间:2026-01-18 13:09:25

|

931人浏览过

|

来源于php中文网

原创

线程上下文切换是操作系统保存当前线程状态并加载目标线程状态的过程,涉及寄存器、栈指针、程序计数器等,由内核调度器触发,常见于Sleep、锁等待、I/O完成等场景。

c# 什么是线程上下文切换 它的开销有多大

线程上下文切换到底发生了什么

线程上下文切换是操作系统把 CPU 控制权从一个线程交给另一个线程的过程。它不是简单地跳转指令,而是要保存当前线程的完整执行状态(包括 寄存器值栈指针程序计数器FPU/SSE/AVX 寄存器 等),再加载目标线程之前保存的状态。这个过程由内核调度器触发,常见于:线程调用 Thread.Sleep()、等待 Monitor.Enter()、I/O 完成、时间片用尽或发生中断。

一次上下文切换典型开销是多少

在现代 x64 Windows 或 Linux 上,一次完整的上下文切换(用户态 → 内核态 → 用户态)通常消耗 1–5 微秒(μs),但实际影响远不止这个数字:

  • CPU 缓存失效:切换后新线程访问的数据大概率不在 L1/L2 缓存中,引发大量缓存缺失(cache miss),可能带来额外几十到上百纳秒延迟
  • TLB 刷新:如果两个线程属于不同进程(即不同虚拟地址空间),页表切换会导致 TLB(Translation Lookaside Buffer)大量失效,进一步拖慢内存访问
  • 调度器开销:Windows 的 KeSwapContext 或 Linux 的 __switch_to 本身需执行数十条指令,还涉及自旋锁、队列操作等
  • 在高并发短任务场景下(如每请求新建线程处理 HTTP 小包),切换开销可能占到总执行时间的 10% 以上

如何观察 C# 中是否频繁发生上下文切换

不能只看 Thread 对象数量——关键看调度行为。推荐以下实测方式:

Replit Agent
Replit Agent

Replit最新推出的AI编程工具,可以帮助用户从零开始自动构建应用程序。

下载
  • 用 Windows 性能监视器(PerfMon)添加计数器:System\Context Switches/sec,持续高于 5000–10000/sec 通常说明存在压力
  • 使用 dotnet-trace 录制并分析:
    dotnet-trace collect --providers Microsoft-Windows-Kernel-Scheduler,Microsoft-DotNETCore-SampleProfiler
    ,查看 Scheduler.Switch 事件密度
  • 避免误判:Task.Run(() => Thread.Sleep(1)) 这类代码会制造“假切换”(线程池线程被阻塞后释放,新任务唤醒另一线程),不代表真实调度压力;真正危险的是同步阻塞 I/O 或 lock 激烈争用

C# 开发中最容易意外引发高频切换的写法

很多看似无害的写法,在高吞吐场景下会成为上下文切换放大器:

  • 在异步方法里写 Thread.Sleep(1)Task.Delay(1).Wait() —— 强制当前线程挂起,调度器必须切走并后续唤醒
  • 密集轮询共享变量:while (!ready) { Thread.Yield(); },每次 Yield() 都是一次轻量级切换请求
  • 过度使用 lock (obj) { ... } 且临界区较长,导致其他线程反复进入等待队列并被唤醒/挂起
  • ASP.NET Core 中用 Task.Run(() => SyncHeavyMethod()) 包裹本可异步的 I/O 操作,把 I/O 等待变成线程池线程空转

上下文切换本身不可见、不报错,但它的代价会以“CPU 使用率不高却响应变慢”“吞吐上不去但线程数飙升”等形式暴露。最有效的缓解方式不是调优切换逻辑,而是从源头减少阻塞和争用——比如用 await stream.ReadAsync() 替代 stream.Read(),用 Channel 替代手动加锁队列。

相关专题

更多
switch语句用法
switch语句用法

switch语句用法:1、Switch语句只能用于整数类型,枚举类型和String类型,不能用于浮点数类型和布尔类型;2、每个case语句后面必须跟着一个break语句,以防止执行其他case的代码块,没有break语句,将会继续执行下一个case的代码块;3、可以在一个case语句中匹配多个值,使用逗号分隔;4、Switch语句中的default代码块是可选的等等。

532

2023.09.21

Java switch的用法
Java switch的用法

Java中的switch语句用于根据不同的条件执行不同的代码块。想了解更多switch的相关内容,可以阅读本专题下面的文章。

412

2024.03.13

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

89

2023.09.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

390

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

572

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

481

2023.08.10

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

61

2025.12.01

Golang channel原理
Golang channel原理

本专题整合了Golang channel通信相关介绍,阅读专题下面的文章了解更多详细内容。

246

2025.11.14

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.3万人学习

Git 教程
Git 教程

共21课时 | 2.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号