目录
这里主要讲解了下
1、future与async的使用。
2、async两种等待方式的区别
3、shared_future的使用
c++标准库提供了两种future:
- std::future<>
- std::shared_future<>
同一个事件仅仅允许关联唯一一个std::future实例,但是可以关联多个shared_future实例。
只要目标事件发生,那么后者关联的所有实例都会同时就绪,并且它们全都可以访问该目标事件关联的任何数据。
future对象本身不提供同步访问。若多个贤臣需要访问同一个future对象,必须用互斥或者其他方式进行保护。
shared_future<>对象可能派生出多个副本,由多个线程分别独占。
#include <iostream>
#include <future>
int main() {
// 使用 std::async 创建一个异步任务
std::future<int> fut = std::async([](){
int sum = 0;
for (int i = 1; i <= 10; ++i) {
sum += i;
}
return sum;
});
// 在主线程中执行其他任务
std::cout << "Other tasks..." << std::endl;
// 等待异步任务完成并获取结果
int result = fut.get();
// 输出结果
std::cout << "Result: " << result << std::endl;
return 0;
}
在这个示例代码中,我们使用 std::async 创建了一个异步任务,它计算 1 到 10 的和,并返回结果。我们将返回值类型设置为 std::future<int>,表示异步任务的返回值是一个 int 类型的值。在主线程中,我们执行了一些其他任务,然后调用 fut.get() 等待异步任务完成并获取结果。最后,我们输出了异步任务的结果。
两种等待方式
默认情况下,std::async()的具体实现会自行决定:
等待future时,是启动新线程还是同步执行任务。
当然也可以用参数显式指定:
- std::launch::async:指定必须另外开启专属的线程,在其上运行任务函数。
- std::launch::deferred:在当前线程上延后调用任务函数,等到在future上调用wait()或者get(),任务函数才会执行
#include <iostream>
#include <future>
int main() {
// 使用 std::async 创建一个异步任务
std::future<int> fut = std::async([](){
int sum = 0;
for (int i = 1; i <= 10; ++i) {
sum += i;
}
return sum;
});
// 在主线程中执行其他任务
std::cout << "Other tasks..." << std::endl;
// 等待异步任务完成并获取结果
int result = fut.get();
// 输出结果
std::cout << "Result: " << result << std::endl;
return 0;
}
在这个示例代码中,我们使用 std::async 创建了一个异步任务,它计算 1 到 10 的和,并返回结果。我们将返回值类型设置为 std::future<int>,表示异步任务的返回值是一个 int 类型的值。在主线程中,我们执行了一些其他任务,然后调用 fut.get() 等待异步任务完成并获取结果。最后,我们输出了异步任务的结果。
两种等待方式
默认情况下,std::async()的具体实现会自行决定:
等待future时,是启动新线程还是同步执行任务。
当然也可以用参数显式指定:
也可以是std::launch::async | std::launch::deferred
使用 std::launch::async 方式:
#include <iostream>
#include <future>
int main() {
// 使用 std::async 创建一个异步任务
std::future<int> fut = std::async(std::launch::async, [](){
int sum = 0;
for (int i = 1; i <= 10; ++i) {
sum += i;
}
return sum;
});
// 在主线程中执行其他任务
std::cout << "Other tasks..." << std::endl;
// 等待异步任务完成并获取结果
int result = fut.get();
// 输出结果
std::cout << "Result: " << result << std::endl;
return 0;
}
,我们使用 std::async 和 std::launch::async 创建了一个异步任务,它计算 1 到 10 的和,并返回结果。std::launch::async 表示异步任务必须在新线程中执行。在主线程中,我们执行了一些其他任务,然后调用 fut.get() 等待异步任务完成并获取结果。最后,我们输出了异步任务的结果。
使用 std::launch::deferred 方式:
#include <iostream>
#include <future>
int main() {
// 使用 std::async 创建一个异步任务
std::future<int> fut = std::async(std::launch::deferred, [](){
int sum = 0;
for (int i = 1; i <= 10; ++i) {
sum += i;
}
return sum;
});
// 在主线程中执行其他任务
std::cout << "Other tasks..." << std::endl;
// 等待异步任务完成并获取结果
int result = fut.get();
// 输出结果
std::cout << "Result: " << result << std::endl;
return 0;
}
在这个示例代码中,我们使用 std::async 和 std::launch::deferred 创建了一个异步任务,它计算 1 到 10 的和,并返回结果。std::launch::deferred 表示异步任务可以在当前线程中延迟执行,直到调用 fut.get() 时才执行。在主线程中,我们执行了一些其他任务,然后调用 fut.get() 等待异步任务完成并获取结果。最后,我们输出了异步任务的结果。
需要注意的是,使用 std::launch::deferred 方式创建的异步任务,如果在调用 fut.get() 之前没有被执行,那么它会在调用 fut.get() 时被执行。如果异步任务抛出了异常,调用 fut.get() 会重新抛出该异常。
std::launch::async 和 std::launch::deferred 两种方式处理计算密集型、IO密集型任务时,各自表现如下:
对于计算密集型任务:
std::launch::async方式:创建一个新线程来执行异步任务,可以充分利用多核 CPU 的性能,提高计算速度。std::launch::deferred方式:在当前线程中延迟执行异步任务,不会创建新线程,因此不会充分利用多核 CPU 的性能,计算速度可能较慢。
对于 IO 密集型任务:
std::launch::async方式:创建一个新线程来执行异步任务,可以避免阻塞当前线程,提高程序的响应速度。std::launch::deferred方式:在当前线程中延迟执行异步任务,不会创建新线程,因此可能会阻塞当前线程,降低程序的响应速度。
std::launch::deferred效果好于std::launch::async的场景:
- 对于一些轻量级的任务,使用
std::launch::deferred可以避免创建新线程的开销,提高程序的性能。 - 对于一些需要保证顺序执行的任务,使用
std::launch::deferred可以保证任务按照顺序执行,避免并发带来的问题。 - 对于一些需要共享数据的任务,使用
std::launch::deferred可以避免线程间的同步和竞争,简化程序的实现。
综上所述,对于计算密集型任务,使用 std::launch::async 方式可以充分利用多核 CPU 的性能,提高计算速度;对于 IO 密集型任务,使用 std::launch::async 方式可以避免阻塞当前线程,提高程序的响应速度。
而使用 std::launch::deferred 方式则不适合处理计算密集型任务,可能会导致程序响应速度较慢;对于 IO 密集型任务,使用 std::launch::deferred 方式可能会阻塞当前线程,降低程序的响应速度。因此,在选择使用 std::launch::async 或 std::launch::deferred 方式时,需要根据具体的任务类型和需求来进行
#include <iostream>
#include <future>
void print_result(std::shared_future<int> fut) {
// 等待异步任务完成并获取结果
int result = fut.get();
// 输出结果
std::cout << "Result: " << result << std::endl;
}
int main() {
// 使用 std::async 创建一个异步任务
std::future<int> fut = std::async([](){
int sum = 0;
for (int i = 1; i <= 10; ++i) {
sum += i;
}
return sum;
});
// 将 std::future 转换为 std::shared_future
std::shared_future<int> shared_fut = fut.share();
// 创建多个线程来等待异步任务完成并获取结果
std::thread t1(print_result, shared_fut);
std::thread t2(print_result, shared_fut);
// 等待线程执行完成
t1.join();
t2.join();
return 0;
}
#include <iostream>
#include <future>
void print_result(std::shared_future<int> fut) {
// 等待异步任务完成并获取结果
int result = fut.get();
// 输出结果
std::cout << "Result: " << result << std::endl;
}
int main() {
// 使用 std::async 创建一个异步任务
std::future<int> fut = std::async([](){
int sum = 0;
for (int i = 1; i <= 10; ++i) {
sum += i;
}
return sum;
});
// 将 std::future 转换为 std::shared_future
std::shared_future<int> shared_fut = fut.share();
// 创建多个线程来等待异步任务完成并获取结果
std::thread t1(print_result, shared_fut);
std::thread t2(print_result, shared_fut);
// 等待线程执行完成
t1.join();
t2.join();
return 0;
}
在这个示例代码中,我们使用 std::async 创建了一个异步任务,它计算 1 到 10 的和,并返回结果。我们将返回值类型设置为 std::future<int>,表示异步任务的返回值是一个 int 类型的值。然后,我们将 std::future 对象转换为 std::shared_future 对象,用于在多个线程中共享异步任务的结果。我们创建了两个线程来等待异步任务完成并获取结果,然后输出结果。
需要注意的是,std::shared_future 可以在多个线程中共享异步任务的结果,而不会重复执行异步任务。在调用 fut.get() 时,如果异步任务还没有完成,当前线程会被阻塞,直到异步任务完成并返回结果。如果异步任务抛出了异常,调用 fut.get() 会重新抛出该异常。
No comments yet.