乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

future 与 async 异步编程

定义与作用

std::async 异步执行任务并返回 std::future 获取结果。std::promise/std::packaged_task 提供更灵活的结果传递机制。

auto future = std::async(std::launch::async, []() {
    return heavyComputation();
});
auto result = future.get();  // 阻塞直到结果就绪

核心原理

future/promise 通信模型

async 启动策略

完整示例

示例一:飞翔科技并行数据聚合

场景说明:白歌用 async 并行查询多个数据库并聚合结果。

#include <iostream>
#include <future>
#include <vector>
#include <string>
#include <chrono>
#include <thread>
#include <iomanip>
#include <numeric>

// 模拟数据库查询
struct QueryResult {
    std::string serverName;
    uint64_t recordCount;
    double avgLoad;
    int latency_ms;
};

QueryResult queryDatabase(const std::string& name, int complexity) {
    auto start = std::chrono::steady_clock::now();

    // 模拟耗时查询
    std::this_thread::sleep_for(std::chrono::milliseconds(complexity));

    auto end = std::chrono::steady_clock::now();
    int lat = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

    return {name, static_cast<uint64_t>(complexity * 1000), complexity * 0.5, lat};
}

int main() {
    std::cout << "=== 飞翔科技并行数据聚合 ===\n\n";

    auto startAll = std::chrono::steady_clock::now();

    // 使用 async 并行查询多个数据库
    auto f1 = std::async(std::launch::async, queryDatabase, "DB-User",     300);
    auto f2 = std::async(std::launch::async, queryDatabase, "DB-Order",    500);
    auto f3 = std::async(std::launch::async, queryDatabase, "DB-Product",  200);
    auto f4 = std::async(std::launch::async, queryDatabase, "DB-Log",      400);

    // 主线程可继续其他工作
    std::cout << "所有查询已发出,主线程可执行其他任务...\n\n";

    // 收集结果
    auto r1 = f1.get();
    auto r2 = f2.get();
    auto r3 = f3.get();
    auto r4 = f4.get();

    auto endAll = std::chrono::steady_clock::now();
    int totalMs = std::chrono::duration_cast<std::chrono::milliseconds>(endAll - startAll).count();

    std::vector<QueryResult> results = {r1, r2, r3, r4};

    // 输出结果
    std::cout << std::left
              << std::setw(14) << "数据库"
              << std::setw(12) << "记录数"
              << std::setw(10) << "平均负载"
              << std::setw(12) << "查询耗时"
              << "\n";
    std::cout << std::string(48, '-') << "\n";

    uint64_t totalRecords = 0;
    double totalLoad = 0;
    for (const auto& r : results) {
        std::cout << std::left
                  << std::setw(14) << r.serverName
                  << std::setw(12) << r.recordCount
                  << std::setw(10) << std::fixed << std::setprecision(1)
                  << r.avgLoad << "%"
                  << std::setw(8)  << (std::to_string(r.latency_ms) + "ms")
                  << "\n";
        totalRecords += r.recordCount;
        totalLoad    += r.avgLoad;
    }

    std::cout << std::string(48, '-') << "\n";
    std::cout << std::left
              << std::setw(14) << "合计"
              << std::setw(12) << totalRecords
              << std::setw(10) << std::fixed << std::setprecision(1)
              << totalLoad << "%"
              << "\n";

    std::cout << "\n总耗时: " << totalMs << "ms";
    int sequentialMs = 300 + 500 + 200 + 400;
    std::cout << " (串行预估: " << sequentialMs << "ms)";
    std::cout << "\n加速比: " << std::fixed << std::setprecision(1)
              << (static_cast<double>(sequentialMs) / totalMs) << "x\n";
}

预期输出:

=== 飞翔科技并行数据聚合 ===

所有查询已发出,主线程可执行其他任务...

数据库         记录数       平均负载    查询耗时
------------------------------------------------
DB-User         300000      150.0%      300ms
DB-Order        500000      250.0%      500ms
DB-Product      200000      100.0%      200ms
DB-Log          400000      200.0%      400ms
------------------------------------------------
合计             1400000     700.0%

总耗时: XXXms (串行预估: 1400ms)
加速比: X.Xx

逐段分析:

  • std::launch::async 强制创建新线程异步执行
  • future.get() 会阻塞,若任务尚未完成则等待
  • 并行执行时间约为最慢任务的时间,而非四者之和
  • 默认策略 async|deferred 由实现决定,不确定时显式指定

示例二:promise 与 packaged_task

场景说明:孔蓝用 promise 实现带回调的异步任务。

#include <iostream>
#include <future>
#include <thread>
#include <string>
#include <chrono>
#include <functional>

// 使用 promise 实现"一次性通知"模式
void deployService(std::promise<std::string>&& prom,
                   const std::string& serviceName) {
    std::cout << "  [部署] 开始部署 " << serviceName << "...\n";

    // 模拟部署过程
    for (int i = 1; i <= 3; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        std::cout << "  [部署] " << serviceName << " 进度: " << (i * 33) << "%\n";
    }

    std::string result = serviceName + " 部署成功 (v2.0.1)";
    prom.set_value(result);  // 设置结果,唤醒 future.get()
}

// 使用 packaged_task 包装可调用对象
std::string buildProject(const std::string& project, int duration) {
    std::this_thread::sleep_for(std::chrono::milliseconds(duration));
    return project + " 构建完成";
}

int main() {
    std::cout << "=== 飞翔科技部署流水线 ===\n\n";

    // 1. promise 模式
    std::promise<std::string> deployPromise;
    std::future<std::string>  deployFuture = deployPromise.get_future();

    std::thread deployThread(deployService,
                             std::move(deployPromise),
                             "飞翔-API-Gateway");

    std::cout << "  部署任务已提交,等待结果...\n";
    std::string deployResult = deployFuture.get();  // 阻塞等待
    std::cout << "  结果: " << deployResult << "\n\n";
    deployThread.join();

    // 2. packaged_task 模式
    std::packaged_task<std::string(const std::string&, int)> buildTask(buildProject);
    std::future<std::string> buildFuture = buildTask.get_future();

    std::cout << "  构建任务已提交...\n";
    std::thread buildThread(std::move(buildTask), "飞翔-Web", 600);
    std::string buildResult = buildFuture.get();
    std::cout << "  结果: " << buildResult << "\n";
    buildThread.join();

    // 3. shared_future(多个消费者)
    std::cout << "\n--- shared_future 广播 ---\n";
    std::promise<int> sharedPromise;
    std::shared_future<int> sf = sharedPromise.get_future().share();

    auto consumer = [](std::shared_future<int> f, const std::string& name) {
        int val = f.get();
        std::cout << "  [" << name << "] 收到通知: " << val << "\n";
    };

    std::future<void> c1 = std::async(std::launch::async, consumer, sf, "李眉");
    std::future<void> c2 = std::async(std::launch::async, consumer, sf, "黄俪");
    std::future<void> c3 = std::async(std::launch::async, consumer, sf, "小崔");

    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    sharedPromise.set_value(42);  // 一次设置,三个消费者都能获取

    c1.get(); c2.get(); c3.get();

    std::cout << "\n所有流水线任务完成\n";
}

预期输出:

=== 飞翔科技部署流水线 ===

  部署任务已提交,等待结果...
  [部署] 开始部署 飞翔-API-Gateway...
  [部署] 飞翔-API-Gateway 进度: 33%
  [部署] 飞翔-API-Gateway 进度: 66%
  [部署] 飞翔-API-Gateway 进度: 99%
  结果: 飞翔-API-Gateway 部署成功 (v2.0.1)

  构建任务已提交...
  结果: 飞翔-Web 构建完成

--- shared_future 广播 ---
  [李眉] 收到通知: 42
  [黄俪] 收到通知: 42
  [小崔] 收到通知: 42

所有流水线任务完成

逐段分析:

  • promise 是"推"模型:工作线程 set_value,调用线程 get
  • packaged_task 包装可调用对象,自动创建 future
  • shared_future 允许多个消费者等待同一结果,通过 share() 从 future 转换
  • promise 必须 move 传递给工作线程(不可拷贝)
  • future.get() 只能调用一次,第二次调用会抛异常

易错场景与面试考点

易错场景

1. future.get() 只能调用一次

auto f = std::async(work);
auto r1 = f.get();  // OK
auto r2 = f.get();  // ❌ 抛出 std::future_error
// 解决:在 get 前调用 f.valid() 检查,或用 shared_future

2. 不保存 async 返回值

std::async(std::launch::async, heavyWork);  // ❌ future 立即析构
// future 析构会阻塞直到任务完成!失去异步意义

auto f = std::async(std::launch::async, heavyWork);  // ✅ 保存

3. promise 生命周期

std::future<int> f;
{
    std::promise<int> p;
    f = p.get_future();
}  // ❌ promise 销毁,但 future 还活着
// 后续 f.get() → broken promise 异常

4. deferred 策略陷阱

// 如果实现选择了 deferred,任务在 get() 执行于当前线程
auto f = std::async(workWithThreadLocal);
f.get();  // 可能不在新线程执行,thread_local 值可能不符预期

面试考点

考点要点
future/promise 模型promise 端写,future 端读,通过共享状态通信
async 策略launch::async(新线程)、launch::deferred(延迟)、默认(实现决定)
packaged_task包装可调用对象,自动关联 future
shared_future可多次 get,多消费者场景
future.get()只能调用一次,之后 valid() 为 false
future.wait()等待但不获取值
future.wait_for/until带超时的等待
broken_promisepromise 未 set_value 就析构
上一页
atomic 与内存序
下一页
std::chrono 时间库