我一直在考虑std::async
以及如何在将来的编译器实现中使用它。但是,现在我有点卡在一些感觉像设计缺陷的东西上。
std::async
几乎与实现有关,可能有两个launch::async
变体,一个将任务启动到新线程,另一个使用线程池/任务调度程序。
但是,根据用于实现std::async
的其中一个变体,使用情况会有很大差异。
对于基于“线程池”的变体,您可以启动许多小任务而不必担心开销,但是,如果其中一个任务在某些时候阻塞了怎么办?
另一方面,“启动新线程”变体不会遇到阻塞任务的问题,另一方面,启动和执行任务的开销会非常高。
线程池: +低开销,永远阻止
推出新主题 +很好的块,高开销
所以基本上取决于实现,我们使用std::async
的方式会非常谨慎。如果我们有一个适用于一个编译器的程序,那么它可能会在另一个编译器上运行得很糟糕。
这是设计的吗?或者我错过了什么?像我一样,你会认为这是一个大问题吗?
在当前规范中,我遗漏了std::oversubscribe(bool)
之类的内容,以便能够实现std::async
的依赖用法。
编辑:据我所知,C ++ 11标准文档没有提供有关发送到std::async
的任务是否可能阻止的任何提示。
答案 0 :(得分:11)
std::async
运行的策略启动的 std::launch::async
任务,就像在新线程中一样“,因此不支持线程池 - 运行时必须拆除并重新创建所有每个任务执行之间的线程局部变量,这不是直截了当的。
这也意味着您可以预期以std::launch::async
策略启动的任务可以同时运行。可能存在启动延迟,如果你有比运行处理器更多的运行线程,那么将会有任务切换,但它们应该正在运行,而不是因为一个人正在等待另一个而死锁。
实现可以选择提供扩展,允许您的任务在线程池中运行,在这种情况下,由该实现来记录语义。
答案 1 :(得分:1)
我希望实现能够启动新线程,并将线程池留给将其标准化的C ++的未来版本。有没有使用线程池的实现?
MSVC最初使用基于其并发运行时的线程池。根据{{3}},这已被删除。 C ++规范为实现者留下了一些空间来做聪明的事情,但是我认为它没有为这个线程池实现留下足够的空间。特别是我认为规范仍然需要销毁和重建thread_local
个对象,但是使用ConcRT的那个线程池不会支持它。