std::async
是一个 C++ 标准库中的函数模板,用于异步执行可调用对象(例如函数、lambda 表达式或函数对象)。它提供了一种简便的方式来启动异步操作,并通过 std::future
对象获取异步操作的结果。下面我将从简单到复杂,一步一步详细解释 std::async
的用法和相关概念。
std::async
的主要作用是异步执行一个任务,并返回一个 std::future
对象,通过这个对象可以获取任务的执行结果或等待任务完成。它的基本语法如下:
template <class Fn, class... Args>
std::future<typename std::result_of<Fn(Args...)>::type> async(std::launch policy, Fn&& fn, Args&&... args);
std::async
支持两种主要的启动策略:
std::launch::async
:任务在新线程中异步执行。std::launch::deferred
:任务延迟执行,直到 std::future
的 get()
或 wait()
被调用时才在当前线程中执行。如果不指定启动策略,默认行为是 std::launch::async | std::launch::deferred
,即实现可以选择异步或延迟执行。
#include
#include
int main() {
// 使用 std::launch::async 在新线程中异步执行
auto future = std::async(std::launch::async, []() {
std::cout << "异步任务执行中..." << std::endl;
return 42;
});
// 获取结果
int result = future.get();
std::cout << "结果: " << result << std::endl;
}
输出:
异步任务执行中...
结果: 42
std::async
返回一个 std::future
对象,可以通过 future.get()
获取异步任务的返回值。如果任务尚未完成,get()
会阻塞当前线程直到任务完成。
get()
只能调用一次,重复调用会导致未定义行为。get()
会重新抛出该异常。#include
#include
int main() {
auto future = std::async(std::launch::async, []() {
throw std::runtime_error("错误");
return 42;
});
try {
int result = future.get(); // 会抛出异常
} catch (const std::exception& e) {
std::cout << "捕获异常: " << e.what() << std::endl;
}
}
输出:
捕获异常: 错误
当使用 std::launch::deferred
时,任务不会立即执行,而是延迟到 future.get()
或 future.wait()
被调用时才在当前线程中执行。
#include
#include
int main() {
auto future = std::async(std::launch::deferred, []() {
std::cout << "延迟任务执行中..." << std::endl;
return 42;
});
// 在这里,任务尚未执行
std::cout << "主线程继续执行..." << std::endl;
// 调用 get() 时,任务在当前线程中执行
int result = future.get();
std::cout << "结果: " << result << std::endl;
}
输出:
主线程继续执行...
延迟任务执行中...
结果: 42
std::async
也可以用于异步调用类的成员函数。需要传递对象的指针或引用,并指定成员函数。
#include
#include
class MyClass {
public:
int add(int a, int b) {
return a + b;
}
};
int main() {
MyClass obj;
auto future = std::async(&MyClass::add, &obj, 3, 4);
int result = future.get(); // result == 7
std::cout << "结果: " << result << std::endl;
}
输出:
结果: 7
可以同时启动多个异步任务,并通过 std::future
管理它们。可以使用 std::future::wait_for
或 std::future::wait_until
来等待任务完成。
#include
#include
int main() {
auto future1 = std::async(std::launch::async, []() {
std::cout << "任务1执行中..." << std::endl;
return 10;
});
auto future2 = std::async(std::launch::async, []() {
std::cout << "任务2执行中..." << std::endl;
return 20;
});
// 等待两个任务完成
int result1 = future1.get();
int result2 = future2.get();
std::cout << "总和: " << (result1 + result2) << std::endl;
}
输出(顺序可能不同):
任务1执行中...
任务2执行中...
总和: 30
如果异步任务抛出异常,std::future::get()
会重新抛出该异常。因此,建议在 get()
调用时使用 try-catch
块来处理可能抛出的异常。
std::async
的对象(尤其是通过引用传递的)在异步任务执行期间保持有效,避免悬垂引用。std::launch::async
时会创建新线程,过多线程可能导致性能下降,因此需要合理管理线程数量。假设我们需要并行计算多个任务的和:
#include
#include
#include
int main() {
std::vector<std::future<int>> futures;
for (int i = 0; i < 5; ++i) {
futures.push_back(std::async(std::launch::async, [i]() {
return i * i;
}));
}
int sum = 0;
for (auto& fut : futures) {
sum += fut.get();
}
std::cout << "总和: " << sum << std::endl; // 0+1+4+9+16=30
}
输出:
总和: 30
std::async
和 std::thread
都是 C++ 标准库中用于并发编程的工具,但它们在设计目的、使用方式和功能特性上有显著的区别。理解这些区别有助于选择适合特定场景的工具。以下是 std::thread
和 std::async
的详细对比。
std::thread
是一个类,代表一个单独的执行线程。创建 std::thread
对象时,会启动一个新线程,并在该线程中执行提供的函数。你需要手动管理线程的生命周期,包括加入(join
)或分离(detach
)线程。
std::async
是一个函数模板,用于异步执行一个函数,并返回一个 std::future
对象。通过这个 std::future
对象,你可以获取异步操作的结果或等待操作完成。std::async
抽象了线程管理的细节,使得异步编程更加简便。
std::thread
std::async
std::thread
std::async
std::future
对象,可以通过 future.get()
直接获取异步操作的结果,简化了数据传递。std::thread
std::async
std::future
中。当调用 future.get()
时,异常会被重新抛出,允许在调用线程中处理。std::thread
std::async
std::launch::async
:在单独的线程中异步执行。std::launch::deferred
:延迟执行,直到调用 future.get()
或 future.wait()
时才在当前线程中执行。std::thread
std::thread
对象通常会启动一个新线程,频繁创建线程可能导致资源消耗较大。std::async
std::launch::async
策略下,可能会重用线程池中的线程,从而提高资源利用效率(具体取决于实现)。std::thread
std::thread
对象销毁前显式调用 join()
或 detach()
,否则程序将终止。std::async
std::future
对象管理异步操作。如果 future
对象在未调用 get()
或 wait()
的情况下被销毁,并且操作是以 std::launch::async
启动的,析构函数可能会阻塞直到操作完成(具体行为取决于实现)。std::thread
std::async
使用 std::thread
#include
#include
void print_hello() {
std::cout << "Hello from thread" << std::endl;
}
int main() {
std::thread t(print_hello);
t.join();
return 0;
}
使用 std::async
#include
#include
int main() {
auto fut = std::async(std::launch::async, []() {
std::cout << "Hello from async" << std::endl;
});
fut.get(); // 等待完成
return 0;
}
说明:两者都能实现异步执行,但 std::async
通过 std::future
提供了更简洁的等待机制。
使用 std::thread
#include
#include
#include
std::mutex mtx;
int result;
void compute_result() {
std::lock_guard<std::mutex> lock(mtx);
result = 42;
}
int main() {
std::thread t(compute_result);
t.join();
std::cout << "Result: " << result << std::endl;
return 0;
}
使用 std::async
#include
#include
int compute_result() {
return 42;
}
int main() {
auto fut = std::async(std::launch::async, compute_result);
std::cout << "Result: " << fut.get() << std::endl;
return 0;
}
说明:std::async
通过 std::future
直接返回结果,代码更简洁且无需手动同步。
使用 std::thread
#include
#include
void throw_exception() {
try {
throw std::runtime_error("Error in thread");
} catch (const std::exception& e) {
std::cout << "Caught in thread: " << e.what() << std::endl;
}
}
int main() {
std::thread t(throw_exception);
t.join();
return 0;
}
使用 std::async
#include
#include
int throw_exception() {
throw std::runtime_error("Error in async");
return 0;
}
int main() {
try {
auto fut = std::async(std::launch::async, throw_exception);
fut.get();
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
}
return 0;
}
说明:std::async
允许在主线程中捕获和处理异步操作中的异常,而 std::thread
要求在线程内部处理。
std::async
(延迟执行)#include
#include
int compute_result() {
std::cout << "Computing result" << std::endl;
return 42;
}
int main() {
auto fut = std::async(std::launch::deferred, compute_result);
std::cout << "Main thread continues" << std::endl;
int result = fut.get(); // 在此处执行 compute_result
std::cout << "Result: " << result << std::endl;
return 0;
}
输出:Main thread continues
Computing result
Result: 42
说明:std::thread
没有直接支持延迟执行的功能。std::thread
和 std::async
都是 C++ 中用于并发编程的重要工具,但它们在设计和使用上有明显的区别:
std::thread
std::async
std::future
轻松获取结果并处理异常。使用 std::thread
使用 std::async