有人告诉过我好几次,我应该使用参数std::async
来触发并忘记类型的任务std::launch::async
(所以它最好在新的执行线程上发挥作用)。
在这些陈述的鼓舞下,我想看看std::async
与以下内容相比如何:
- 顺序执行
- 一个简单的分离
std::thread
- 我简单的异步“实现”
我天真的异步实现如下所示:
template <typename F, typename... Args>
auto myAsync(F&& f, Args&&... args) -> std::future<decltype(f(args...))>
{
std::packaged_task<decltype(f(args...))()> task(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
auto future = task.get_future();
std::thread thread(std::move(task));
thread.detach();
return future;
}
这里没有什么花哨的,将仿函数与其参数一起打包f
成一个,在一个分离的新对象上启动它,然后从任务中返回。std::packaged task
std::thread
std::future
现在测量执行时间的代码std::chrono::high_resolution_clock
:
int main(void)
{
constexpr unsigned short TIMES = 1000;
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < TIMES; ++i)
{
someTask();
}
auto dur = std::chrono::high_resolution_clock::now() - start;
auto tstart = std::chrono::high_resolution_clock::now();
for (int i = 0; i < TIMES; ++i)
{
std::thread t(someTask);
t.detach();
}
auto tdur = std::chrono::high_resolution_clock::now() - tstart;
std::future<void> f;
auto astart = std::chrono::high_resolution_clock::now();
for (int i = 0; i < TIMES; ++i)
{
f = std::async(std::launch::async, someTask);
}
auto adur = std::chrono::high_resolution_clock::now() - astart;
auto mastart = std::chrono::high_resolution_clock::now();
for (int i = 0; i < TIMES; ++i)
{
f = myAsync(someTask);
}
auto madur = std::chrono::high_resolution_clock::now() - mastart;
std::cout << "Simple: " << std::chrono::duration_cast<std::chrono::microseconds>(dur).count() <<
std::endl << "Threaded: " << std::chrono::duration_cast<std::chrono::microseconds>(tdur).count() <<
std::endl << "std::sync: " << std::chrono::duration_cast<std::chrono::microseconds>(adur).count() <<
std::endl << "My async: " << std::chrono::duration_cast<std::chrono::microseconds>(madur).count() << std::endl;
return EXIT_SUCCESS;
}
哪里someTask()
有一个简单的方法,在这里稍等一下,模拟完成的一些工作:
void someTask()
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
最后,我的结果:
- 顺序:1263615
- 线程:47111
- 标准::同步:821441
- 我的异步:30784
谁能解释这些结果?它似乎std::aysnc
比我的幼稚实现慢得多,或者只是简单而简单的detached std::thread
s。为什么会这样?在这些结果之后还有什么理由使用std::async
?
(请注意,我也用 clang++ 和 g++ 做了这个基准测试,结果非常相似)
更新:
阅读 Dave S 的回答后,我将我的小基准更新如下:
std::future<void> f[TIMES];
auto astart = std::chrono::high_resolution_clock::now();
for (int i = 0; i < TIMES; ++i)
{
f[i] = std::async(std::launch::async, someTask);
}
auto adur = std::chrono::high_resolution_clock::now() - astart;
所以std::future
s 现在没有被破坏 - 并因此加入 - 每次运行。在代码中进行此更改后,std::async
会产生与我的 implementation & detached 类似的结果std::thread
。