(七)异步编程
异步编程(Asynchronous Programming)是一种编程模型,它允许程序在等待某个操作(如I/O操作、网络请求等)完成时,不阻塞当前线程的执行。在并发编程中,可以使用异步编程来避免线程阻塞,提高资源的利用率。异步编程可以看作是并发编程的一种策略或技术。 C++ 标准库中的std::future 和 std::async 用于支持异步编程。
- std::async 是一个函数模板,它用于启动一个异步任务。这个函数接受一个可调用的对象(如函数、Lambda 表达式、函数对象等)作为参数,并在一个单独的线程(或可能是线程池中的线程,具体取决于实现)上异步执行它。std::async 返回一个 std::future 对象,该对象持有异步操作的结果。
- std::future 是一个模板类,用于表示异步操作的结果。当你调用 std::async 来启动一个异步任务时,它会返回一个 std::future 对象。你可以使用这个对象来检查异步操作是否完成(通过 std::future::valid() 或 std::future::wait_for()/std::future::wait_until() 方法),或者获取异步操作的结果(通过 std::future::get() 方法)。
下面展示如何使用 std::future 和 std::async 来异步计算一个数的平方:
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
// 计算平方的函数
int square(int x) {
auto start = std::chrono::system_clock::now();
// 为了模拟一个耗时的操作,我们让线程休眠一段时间
std::this_thread::sleep_for(std::chrono::seconds(2));
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "Square computation took " << diff.count() << " seconds.\n";
return x * x;
}
int main() {
auto start_main = std::chrono::system_clock::now();
// 使用 std::async 启动一个异步任务,并传递 square 函数和参数 5
std::future<int> result = std::async(std::launch::async, square, 5);
std::cout << "Square computation is in progress...\n";
// 模拟主线程执行其他任务
std::this_thread::sleep_for(std::chrono::seconds(1));
auto after_other_task = std::chrono::system_clock::now();
std::chrono::duration<double> diff_other_task = after_other_task - start_main;
std::cout << "Main thread did something else after " << diff_other_task.count() << " seconds.\n";
// 调用 get() 获取square 函数的结果
// 注意:调用 get() 函数会阻塞当前线程,直到结果可用
int value = result.get();
// 输出结果和获取结果所用的时间
auto end_main = std::chrono::system_clock::now();
std::chrono::duration<double> diff_result = end_main - start_main;
std::cout << "The square of 5 is " << value << ". Got result after " << diff_result.count() << " seconds.\n";
return 0;
}
Square computation is in progress...
Main thread did something else after 1.01517 seconds.
Square computation took 2.0062 seconds.
The square of 5 is 25. Got result after 2.00861 seconds.
在这个示例中,异步任务(计算5的平方)需要2秒钟来完成。然而,主线程在启动异步任务后立即继续执行,并在1秒钟后输出“Main thread is doing something else...”。这表明主线程在等待异步任务完成期间没有被阻塞,而是继续执行了其他任务。最后,当主线程需要异步任务的结果时,它调用result.get(),这时如果异步任务还没有完成,主线程将会被阻塞,直到结果可用。