当前位置:网站首页>Item 36: Specify std::launch::async if asynchronicity is essential.
Item 36: Specify std::launch::async if asynchronicity is essential.
2022-08-01 00:23:00 【loongknown】
Item 36: Specify std::launch::async if asynchronicity is essential.
当你使用 std::async()
执行一个函数或可调用对象时,你通常期望这个函数是异步执行。但是, std::async()
不一定如你所愿。其实 std::async()
是根据执行策略决定是否会异步执行。 std::async()
有两种执行策略,定义在 std::launch
作用域中:
std::launch::async
函数或可执行对象必须异步执行,也即运行在其他线程上。std::launch::deferred
函数或可执行对象延迟执行。仅在std::async()
的返回对象std::future
调用get
或wait
时,才在当前线程同步执行,并且调用者会阻塞直到函数执行完成。
std::async()
的默认策略其实是二者的组合,也即以下两者涵义完全相同:
auto fut1 = std::async(f); // run f using default launch policy
auto fut2 = std::async(std::launch::async | // run f either
std::launch::deferred, // async or
f); // deferred
默认的策略下,f
可能是同步执行也可能是异步执行。正如 Item 35: Prefer task-based programming to thread-based. 中讨论的:标准库的线程管理模块承担了线程的创建和释放的职责,可以有效避免超额订阅、保证负载均衡。这极大地方便了 std::async
的使用。
但是,默认策略也会有如下问题:
- 无法预测
f
是否是并发执行。 - 无法预测
f
是否运行在get
或wait
调用时的线程上。 - 甚至无法预测
f
是否已经执行了。因为没法保证一定会调用get
或wait
。
当 f
要访问本地线程存储(TLS,Thread Local Storage)时,无法预测访问的是哪个线程的本地存储。
auto fut = std::async(f); // TLS for f possibly for
// independent thread, but
// possibly for thread
// invoking get or wait on fut
std::async
的默认策略还会影响到 wait_for
超时调用写法,可能导致 bug,例如:
using namespace std::literals; // for C++14 duration suffixes; see Item 34
void f() // f sleeps for 1 second, then returns
{
std::this_thread::sleep_for(1s);
}
auto fut = std::async(f); // run f asynchronously (conceptually)
while (fut.wait_for(100ms) != // loop until f has
std::future_status::ready) // finished running...
{
// which may never happen!
…
}
如果 std::async
是并发执行,也即执行策略为 std::launch::async
,以上代码没有问题。但是,如果执行策略为 std::launch::deferred
时,fut.wait_for
总是返回 future_status::deferred
,以上代码就会有问题。解决办法也很简单,先通过 wait_for
的超时时间为 0 来检测 std::async
是异步执行还是同步执行:
auto fut = std::async(f); // as above
if (fut.wait_for(0s) == // if task is
std::future_status::deferred) // deferred...
{
// ...use wait or get on fut
… // to call f synchronously
} else {
// task isn't deferred
while (fut.wait_for(100ms) != // infinite loop not
std::future_status::ready) {
// possible (assuming
// f finishes)
… // task is neither deferred nor ready,
// so do concurrent work until it's ready
}
… // fut is ready
}
综上,如果你的使用场景不是以下几种,则需要考虑是否需要替换 std::async
的默认策略:
- 当调用
get
或wait
时,任务不需要并发执行。 - 并不关心访问的是哪个线程的本地存储。
- 可以保证
get
或wait
一定会被调用,或者任务不被执行也能接受。 - 使用
wait_for
或wait_until
时,需要考虑std::launch::deferred
策略。
如果不是以上场景,你可能需要指定使用 std::launch::async
策略,也即真正创建一个线程去并发执行任务:
auto fut = std::async(std::launch::async, f); // launch f asynchronously
这里提供一个并发执行任务的封装:
template<typename F, typename... Ts> // C++11
inline
std::future<typename std::result_of<F(Ts...)>::type>
reallyAsync(F&& f, Ts&&... params) // return future
{
// for asynchronous
return std::async(std::launch::async, // call to f(params...)
std::forward<F>(f),
std::forward<Ts>(params)...);
}
reallyAsync
接受一个可执行对象 f
和 多个参数 params
,并完美转发给 std::async
,同时使用 std::launch::async
策略。C++14 版本如下:
template<typename F, typename... Ts>
inline
auto // C++14
reallyAsync(F&& f, Ts&&... params)
{
return std::async(std::launch::async,
std::forward<F>(f),
std::forward<Ts>(params)...);
}
至此,本文结束。
参考:
边栏推荐
- Nmap Operation Manual - Full Version
- 2022年最新重庆建筑八大员(电气施工员)模拟题库及答案
- Shell common scripts: Nexus batch upload local warehouse enhanced version script (strongly recommended)
- 推荐系统:常用评价指标总结【准确率、精确率、召回率、命中率、(归一化折损累计增益)NDCG、平均倒数排名(MRR)、ROC曲线、AUC(ROC曲线下的面积)、P-R曲线、A/B测试】
- Notes on how to use zeno
- NIO programming
- 继承的注意事项
- 基于simulink的Passive anti-islanding-UVP/OVP and UFP/OFP被动反孤岛模型仿真
- Xinao Learning Plan The Road to Informatics Competition (2022.07.31)
- Flutter教程之四年开发经验的高手给的建议
猜你喜欢
【MATLAB项目实战】LDPC-BP信道编码
消息队列消息存储设计(架构实战营 模块八作业)
C# Rectangle基本用法和图片切割
清华大学陈建宇教授团队 | 基于接触丰富机器人操作的接触安全强化学习框架
Handwritten a simple web server (B/S architecture)
Shell common scripts: Nexus batch upload local warehouse enhanced version script (strongly recommended)
《ArchSummit:时代的呐喊,技术人听得到》
【云驻共创】【HCSD大咖直播】亲授大厂面试秘诀
如何设计高可用高性能中间件 - 作业
硬件设备计算存储及数据交互杂谈
随机推荐
cobaltstrike
清华大学陈建宇教授团队 | 基于接触丰富机器人操作的接触安全强化学习框架
zeno使用方法笔记
lua入门案例实战123DIY
Thinking and Implementation of Object Cache Service
MYSQL二阶段提交
助力数字政府建设,中科三方构建域名安全保障体系
Web3.0: Building an NFT Market (1)
Web API 介绍和类型
pycaret source code analysis: download dataset\Lib\site-packages\pycaret\datasets.py
Nmap Operation Manual - Full Version
谷歌『云开发者速查表』;清华3D人体数据集;商汤『通用视觉框架』公开课;Web3极简入门指南;高效深度学习免费书;前沿论文 | ShowMeAI资讯日报
C# Rectangle basic usage and picture cutting
Nmap 操作手册 - 完整版
LeetCode--The problem of robbery
南方科技大学:Xiaoying Tang | AADG:视网膜图像分割领域泛化的自动增强
Binary tree traversal non-recursive program -- using stack to simulate system stack
NIO编程
qlib量化源码分析:qlib/qlib/contrib/model/gbdt.py
MVCC总结