mat*_*ort 34

这不是一个或两件事 - 你可以使用手工创建的std :: threads进行期货(连同promises).使用std::async是一种方便的方法来触发一个线程进行一些异步计算,并通过未来封送结果,但std::async在当前标准中相当有限.如果接受来自Microsoft PPL的一些想法的建议扩展,它将变得更有用.

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

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

Bartosz Milewski讨论了std::async目前在他的文章" C++ 11中的异步任务:不是很有趣"中指出的方法的一些局限性

  • 以下是Bjarne Stroustroup关于异步的内容:...甚至没有想到使用async()来启动执行I/O,操作互斥锁或以其他方式与其他任务交互的任务.async()背后的想法与range-for语句背后的想法相同:提供一种简单的方法来处理最简单,相当常见的情况,并将更复杂的示例留给完全通用的机制. (11认同)
  • 正常创建和连接好的线程是你想要避免高效代码的问题:)这就是std :: async的问题 - 它很可能通过触发新线程而不是线程池来实现.如果您需要高效的细粒度线程工作负载,通常需要类似线程池的东西. (2认同)

小智 6

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

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


Sha*_*ath 6

我意识到这个问题提出已经有8年了。从那时起,C++ 并发环境发生了很大变化。最近我也不得不在这片风景中徘徊,不知道该走哪条路继续前进。我想分享一些我的想法,并可能得到验证。我会将原来的问题稍微修改为 std::async vs 线程池,而不仅仅是 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));
}
Run Code Online (Sandbox Code Playgroud)

任务队列 _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)。所以你可以说,当我看到周围出现的所有新变化时,我有点害怕害怕错过。请原谅,在查看了 std::async 和协程之后,我不明白它们如何帮助像我这样已经习惯使用 io_service + 线程池模型的人。它看起来更昂贵,而且我无法控制优先级或线程创建,不同编译器的实现有所不同

我发现,与分散到多个函数对象中的异步功能相比,它使函数显得同步且结构化(所有部分都集中在一个地方)。

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


Rob*_*ert 5

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

  • 如果您将“std::thread”与“std::packaged_task”一起使用,则可以进行轮询。 (3认同)