75

任何人都可以给出关于何时使用它们的高级直觉吗?

参考:

4

4 回答 4

52

这并不是一个非此即彼的事情——您可以将期货(连同承诺)与手动创建的 std::threads 一起使用。Usingstd::async是一种为某些异步计算触发线程并通过未来将结果编组回来的便捷方法,但std::async在当前标准中相当有限。如果采纳微软 PPL 中包含一些想法的建议扩展,它将变得更加有用。

目前,std::async对于相当简单的程序,它可能最适合处理非常长时间运行的计算或长时间运行的 IO。虽然它并不能保证低开销(实际上它的指定方式使得在后台使用线程池难以实现),因此它不太适合更细粒度的工作负载。为此,您需要使用std::thread或使用 Microsoft 的 PPL 或 Intel 的 TBB 之类的东西来滚动您自己的线程池。

您还可以使用std::thread以更现代和可移植的方式编写的“传统”POSIX 线程样式代码。

Bartosz Milewski在他的文章Async Tasks in C++11: Not Quite There Yet 中std::async讨论了当前指定方式的一些限制

于 2014-09-12T18:21:31.683 回答
10

我发现的一个简单原因是当您想要一种方法来检测(通过轮询)异步作业是否完成时。使用std::thread,您必须自己管理它。std::async您可以查询std::future::valid()(或使用)std::future::wait_for/wait_until(...)以了解何时完成。

于 2016-12-14T12:40:12.337 回答
7

使用std::futrueover的一个用例std::thread是您想调用一个返回值的函数。当你想要函数的返回值时,你可以调用get()future的方法。

std::thread不提供获取函数返回值的直接方法。

于 2020-11-26T18:33:28.463 回答
1

我意识到这个问题提出已经 8 年了。从那时起,C++ 并发环境发生了很大变化。最近我也不得不在这片风景中徘徊,不知道该走哪条路才能前进。我想分享我的一些想法,并可能得到验证。我会将原始问题稍微修改为 std::async 与线程池,而不仅仅是 std::thread。

自 2011 年以来,我一直在大量使用 boost::thread_group 和 boost::asio::io_service 分别用于线程池和事件循环。我的每个应用程序都是这样开始的:

int noOfCores = boost::thread::hardware_concurrency();
for (int i = 0; i < noOfCores; i++)
{
    _threadPool.create_thread(boost::bind(&pri_queue::run, &_taskQueue));
}

任务队列 _taskQueue 的类型 pri_queue 有点类似于这个boost 示例,除了我的 run() 函数等待 io_service.run_one()。因此,我还通过在排队时分配优先级来控制任务执行的优先级。

在此之后,我可以使用 post() 在此队列中抛出任何函数(使用 boost::bind 绑定参数)以执行,或者使用 boost::asio::deadline_timer::async_wait() 延迟调度它。

由于我的框架中的所有内容都是事件驱动的,因此我很乐意将任何功能划分为多个功能对象,同时等待诸如异步 http 客户端的 boost 示例中的事件。这个模型经过了非常长时间的测试,没有线程创建成本,因为每个线程都是预先创建的。

然而,自从我在公司的所有产品中采用这个模型以来,C++ 标准已经更新了 3 次(14、17、20)。因此,当我看到周围出现的所有新变化时,您可以说我正在遭受一些 FOMO 之苦。请原谅我,在查看了 std::async 和协程之后,我看不出它们如何帮助像我这样已经习惯使用 io_service + 线程池模型的人。它看起来更昂贵,而且我无法控制优先级或线程创建,不同编译器的实现不同。

我看到它使函数看起来是同步的和结构化的(所有部分都在一个地方),与溢出到多个函数对象中的异步功能相比。

对于 C++ 的老手,我会说线程池比 std::async 甚至协程更好。当然,如果应用程序不是事件驱动的,或者如果您不熟悉异步编程,std::async 会更容易处理。

于 2022-01-13T11:07:16.147 回答