C++ 异步编程组件
C++ 异步编程组件
在现代多线程编程中,异步任务处理是提高程序性能的关键。本文将通过几个简单的示例,展示如何使用 C++ 中的 std::promise, std::future, 和 std::async 来实现高效的任务并行化。
一个可拆解的任务
假设我们需要计算从 [1, N) 范围内所有数字的总和。为了演示目的,我们将这个大任务拆分为两个子任务,分别由主线程和工作线程执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <thread>
#include <future>
#include <stdexcept>
using namespace std;
const int N = 1e8;
int large_task(int s, int e) {
int sum = 0;
for (int i = s; i < e; ++i)
sum += i;
return sum;
}
// 示例函数,用于演示异常处理
int large_task_throw_error(int s, int e) {
throw runtime_error("throw a exception");
int sum = 0;
for (int i = s; i < e; ++i)
sum += i;
return sum;
}
使用 promise 和 future 实现任务并行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
std::promise<int> p; // 定义一个 promise,用于存储将来返回的结果
std::future<int> f = p.get_future(); // 获取与 promise 关联的 future
// 启动工作线程,计算 [1, N/2) 区间的总和
std::thread t1([&p]() {
int result = large_task(1, N / 2);
p.set_value(result); // 设置结果值
});
// 主线程计算 [N/2, N) 区间的总和
int result = large_task(N / 2, N);
// 等待工作线程完成,并获取其结果
result += f.get();
cout << "Total result = " << result << endl;
// 确保工作线程已结束
t1.join();
在这个例子中,我们通过 std::promise 和 std::future 实现了任务的并行执行。promise 在工作线程中设置结果值,而 future 在主线程中等待并获取该结果。这种方式允许我们在不同的线程之间进行有效的通信。
使用 async 和 future 实现任务并行
相比于手动管理线程,std::async 提供了一种更简洁的方式来启动异步任务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 使用 async 启动异步任务,并获取其返回值
auto fut = std::async(std::launch::async, []() {
// Uncomment the next line to simulate an exception
// return large_task_throw_error(0, N / 2);
return large_task(1, N / 2);
});
// 主线程计算 [N/2, N) 区间的总和
int out = large_task(N / 2, N);
cout << "Main thread return: " << out << endl;
try {
int return_param = fut.get(); // 获取异步任务的结果
cout << "Result value: " << out + return_param << endl;
} catch (const std::exception& e) {
cerr << e.what() << '\n'; // 捕获并处理可能的异常
}
这里,std::async 自动为我们创建了一个新线程来执行指定的任务,并返回一个 std::future 对象。我们可以调用 .get() 方法来等待任务完成并获取其结果。如果任务抛出异常,该异常会通过 future::get() 抛出并在主线程中被捕获。
总结
C++ 中的 std::promise, std::future, 和 std::async 是强大的异步编程工具,能够帮助我们轻松实现任务的并行化和线程间通信。
std::promise:用于在一个线程中设置结果或异常,另一个线程可以通过关联的std::future获取这些信息。std::future:提供了一种机制,使得可以在未来的某个时刻获取异步操作的结果或异常。std::async:简化了异步任务的启动过程,自动管理线程的创建和销毁。
通过合理利用这些组件,可以显著提升程序的性能,特别是在多核处理器上运行时效果更加明显。
善用异步编程组件,将可拆解的大任务合理拆分成多个子任务,可以得到极致的性能表现,尤其是在多核场景下加速效果尤为显著。
本文由作者按照 CC BY 4.0 进行授权