You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何《C++并发编程实战》中代码2的std::experimental::future实现更优?

代码1与代码2的异步实现差异解析

两段代码均出自《C++并发编程实战第2版》,用于模拟用户登录的三步流程:身份验证→请求账户信息→更新显示。二者的核心差异在于是否实现了真正的异步IO,以下是具体拆解:

代码1的执行逻辑(伪异步)

先看spawn_async模板函数:它的本质是创建新线程同步执行传入的函数,再用promise/future包装执行结果。具体到process_login流程:

  1. 调用spawn_async时,会启动一个新线程,在该线程中同步阻塞执行backend.authenticate_user——这个线程会一直等待后端返回验证结果,期间完全闲置,直到IO完成才通过promise传递结果。
  2. 第一个then回调被触发后,id.get()会阻塞当前执行回调的线程,同步调用backend.request_current_info,同样要等待IO完成才能进入下一个回调。
  3. 整个流程的每一步IO操作,都对应一个被阻塞的线程,线程资源在IO等待期间被浪费,属于用多线程模拟异步的伪异步实现。
template<typename Func>
std::experimental::future<decltype(std::declval<Func>()())>
spawn_async(Func&& func){
  std::experimental::promise<
    decltype(std::declval<Func>()())> p;
  auto res=p.get_future();
  std::thread t(
    [p=std::move(p),f=std::decay_t<Func>(func)]()
      mutable{
      try{
        p.set_value_at_thread_exit(f());
      } catch(...){ 
        p.set_exception_at_thread_exit(std::current_exception());
      }
  });
  t.detach();
  return res;
}

std::experimental::future<void> process_login( 
  std::string const& username, std::string const& password)
{
  return spawn_async([=](){
    return backend.authenticate_user(username, password);  
  }).then([](std::experimental::future<user_id> id){
    return backend.request_current_info(id.get());
  }).then([](std::experimental::future<user_data> info_to_display){
    try{
      update_display(info_to_display.get());
    } catch(std::exception& e){
      display_error(e);
    }
  });
}

代码2的执行逻辑(真异步)

代码2依赖backend提供的async_*方法,这些方法是基于操作系统异步IO机制实现的真正异步操作:

  1. backend.async_authenticate_user发起身份验证请求后,会立即返回future,不会阻塞任何线程——底层会利用IO多路复用(如epoll、kqueue)或异步IO接口(如IOCP)等待后端响应,等待期间线程可以被调度去处理其他任务。
  2. 当验证完成、future就绪时,第一个then回调触发,调用backend.async_request_current_info同样是发起异步请求,立即返回future,无线程阻塞。
  3. 整个流程没有线程在IO等待期间闲置,仅在回调需要执行计算逻辑时占用线程,线程利用率极高,是真正的异步编程模式。
std::experimental::future<void> process_login(
  std::string const& username, std::string const& password)
{
  return backend.async_authenticate_user(username, password).then(
    [](std::experimental::future<user_id> id){
      return backend.async_request_current_info(id.get());      
    }).then([](std::experimental::future<user_data> info_to_display){
      try{
        update_display(info_to_display.get());  
      } catch(std::exception& e){
        display_error(e);
      }
    });
}

核心差异总结

  • 线程资源利用:
    • 代码1:每一步IO操作都占用一个阻塞线程,高并发场景下会创建大量线程,导致上下文切换开销剧增,系统资源耗尽。
    • 代码2:仅在回调执行时占用线程,IO等待无阻塞,少量线程即可支撑大量并发请求,扩展性极强。
  • 异步本质:
    • 代码1是"线程化的同步":用多线程让主线程不阻塞,但工作线程仍在同步等待IO,没有摆脱阻塞模型。
    • 代码2是"非阻塞异步IO":依赖操作系统底层机制实现无等待的IO请求,是异步编程的核心实现方式。
  • 性能表现:
    • 代码1在低并发场景下看似正常,但高并发时性能急剧下降。
    • 代码2的性能不会随并发量线性恶化,能高效处理大规模IO密集型任务。

内容的提问来源于stack exchange,提问作者牛牪犇

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:50:19