基于任务的编程优于基于线程的编程

发布: (2026年3月7日 GMT+8 08:06)
3 分钟阅读
原文: Dev.to

Source: Dev.to

更倾向于基于任务的编程而非基于线程的

如果你想异步运行某些工作,有两种基本选择:std::threadstd::async

int doAsyncWork();

std::thread th(doAsyncWork); // 基于线程

使用 std::async(推荐)

auto future = std::async(doAsyncWork);

std::async(doAsyncWork) 会创建一个 任务
任务更优,因为它返回一个 std::future,可以用来同步程序。future 提供 get() 方法来获取结果或重新抛出工作函数抛出的任何异常。任务还提供了更高层次的抽象。

什么是线程?

  • 硬件线程 – CPU 提供的物理执行单元。现代 CPU 每个核心可能暴露一个或多个硬件线程。
  • 软件线程(操作系统或系统线程) – 由操作系统管理的抽象,调度到硬件线程上运行。
  • std::thread 对象是底层软件线程的句柄。

软件线程是一种有限资源。创建的线程数超过系统能够提供的数量会抛出 std::system_error(即使在 noexcept 函数中也是如此)。

即使没有耗尽线程池,过度订阅 也可能发生:就绪运行的软件线程数量多于可用的硬件线程,导致频繁的上下文切换和额外的开销。

为什么更倾向于 std::async

std::async 将线程创建和调度的管理交给实现。使用 std::async 创建的任务通常可以避免过度订阅问题,因为它 不保证 会创建新的软件线程。相反,调度器可以在需要结果时在已有线程上运行该函数。

当使用默认的启动策略时,实现可以在异步执行(新线程)和延迟执行(同一线程)之间进行选择。

启动策略

策略行为
std::launch::async保证函数在新线程上运行。
std::launch::deferred函数 不会 立即运行。只有在调用 future.get()future.wait() 时才执行,且在调用线程上运行。
默认 (std::launch::async | std::launch::deferred)实现自行决定是异步运行任务(新线程)还是延迟运行(同一线程,惰性执行)。

使用带有适当启动策略的 std::async,可以编写更清晰、更安全的异步代码,而无需手动处理线程生命周期和过度订阅问题。

0 浏览
Back to Blog

相关文章

阅读更多 »