我们知道,std::async
函数用于异步执行一个任务,返回一个std::future
对象,该对象最终将持有函数的返回值。
std::async
可以接受一个启动策略作为其第一个参数,这些策略决定了任务的执行方式。C++标准提供了两种启动策略:std::launch::async
和std::launch::deferred
。
std::launch::async
当使用std::launch::async
作为std::async
的启动策略时,函数保证在另一个线程上异步启动。
也就是说任务将独立于主线程的执行流,立即开始执行。使用这种启动策略时,系统会创建一个新线程(或从线程池中获取一个线程)来执行该任务。由于任务是并行执行的,它可以利用多核处理器的优势。
auto future = std::async(std::launch::async, []{
// 长时间运行的任务
return "Result of the task";
});
std::launch::deferred
当使用std::launch::deferred
作为启动策略时,任务并不是立即执行的。
相反,任务被延迟执行,直到调用std::future::get()
或std::future::wait()
时才开始执行,并且是在调用线程上同步执行的。
如果你从不请求结果(即不调用get()
或wait()
),那么延迟的任务将永远不会执行。
auto future = std::async(std::launch::deferred, []{
// 长时间运行的任务
return "Result of the task";
});
// 任务在这里被延迟执行,直到future.get()被调用
auto result = future.get(); // 在这一点,任务开始执行并阻塞直到完成
没有指定策略
如果在调用std::async
时没有指定启动策略,则实现(编译器/标准库)可以自行选择是立即在新线程上执行任务(类似于std::launch::async
),还是延迟执行(类似于std::launch::deferred
)。
这提供了灵活性,但可能导致不确定的行为,因为不同的实现可能会选择不同的默认行为。
使用建议
- 对于需要并发执行的长时间运行的任务,或者不想阻塞当前线程的操作,使用
std::launch::async
。 - 对于可能不需要立即执行的任务,或者希望延迟决定是否执行任务的情况,可以使用
std::launch::deferred
。 - 明确指定启动策略可以让你的代码行为更加可预测,特别是在设计需要明确行为的库或框架时。
std::async
提供了一种高级的异步执行机制,可以在不直接管理线程的情况下,执行后台任务。通过合理选择启动策略,可以使代码既能充分利用多核处理器,又能保持逻辑的清晰和简洁。