c++的协程和线程有什么区别 如何选择合适的并发模型【详解】

10次阅读

协程更适用于 I / O 密集或高并发场景;线程由操作系统调度、开销大,协程用户态调度、栈小切换快,10 万连接用线程内存超 100GB 而协程可行。

c++ 的协程和线程有什么区别 如何选择合适的并发模型【详解】

协程和线程是 C ++ 中两种不同层级的并发抽象:线程由 操作系统 调度,对应真实 CPU 执行单元;协程由用户态代码控制调度,本质是可挂起恢复的函数。选线程还是协程,关键看任务类型——CPU 密集用线程,I/ O 密集或高并发场景协程更轻量高效。

调度机制与资源开销差异明显

线程由内核调度,创建销毁需系统调用,上下文切换涉及寄存器、内存映射等,单线程 默认 1MB 左右;协程在用户态协作式调度(C++20 `co_await` + 自定义 awaiter),栈可按需分配(如几 KB),切换只需保存 / 恢复少量寄存器和栈指针,开销低两个数量级以上。

  • 10 万并发连接用线程:内存占用 超 100GB,几乎不可行

适用场景有明确分界

线程适合需要真正并行执行的任务,比如图像处理、矩阵运算、物理模拟等 CPU 密集型工作;协程适合大量等待 I /O(网络请求、数据库查询、文件读写)的场景,尤其是服务端需同时处理数万客户端连接时。

  • Web 服务器处理 HTTP 请求:每个请求用协程封装,等待 socket 读写时不阻塞其他协程
  • 实时音视频编码:必须利用多核并行,应使用线程池 +OpenMP 或 std::thread
  • 混合场景(如游戏服务器):用线程池处理逻辑计算,协程处理网络收发

C++20 协程不是“开箱即用”的线程替代品

C++20 只提供协程语法(co_awaitco_yieldco_return)和底层原语,不带运行时调度器。你得自己实现或选用第三方库(如 Boost.Asio 1.70+、cppcoro、libunifex)来管理协程生命周期和唤醒逻辑。而线程直接用 std::threadstd::jthread即可启动。

立即学习C++ 免费学习笔记(深入)”;

  • 新手建议从 Boost.Asio 的 awaitable 入手,它封装了 IO 调度,API 较友好
  • 避免手写调度器,除非明确需要极致定制(如嵌入式低延迟场景)
  • 协程函数返回类型必须满足 promise_type 协议,编译器据此生成状态机,不是所有函数都能加co_await

错误混用会导致严重问题

在协程中直接调用阻塞 API(如 sleep(1)fread、未设非阻塞的recv)会卡住整个线程上的所有协程;反过来,在线程中滥用协程(比如在std::thread 里启动大量未绑定调度器的协程)会导致协程永远不被唤醒。

  • 网络 I / O 务必用异步接口(如async_read)配合co_await
  • CPU 密集操作别放在协程里跑太久,应切片或交还调度器(如co_await std::experimental::suspend_always{}
  • 跨线程访问协程对象需注意生命周期——协程可能在另一线程恢复,确保捕获的变量仍有效

以上就是

text=ZqhQzanResources