安东尼·威廉书中的台词:
表示函数调用是 推迟到未来调用std::launch::deferred
或wait()
时。get()
X baz(X&); auto f7 = std::async(std::launch::deferred, baz, std::ref(x)); //run in wait() or get() //... f7.wait(); //invoke deferred function
此代码相对于直接调用(
baz(ref(x))
)有什么好处或区别?
换句话说,这里拥有未来有什么意义?
假设你有一个线程池。
线程池拥有一定数量的线程。说10.
当您添加任务时,它们会返回一个 future,并在池中排队。
池中的线程醒来,获取任务并处理它。
当该池中有 10 个任务等待队列中稍后的任务时,会发生什么?好吧,陷入僵局。
现在,如果我们从这个池中返回一个延期的未来会怎样。当您等待这个延迟的未来时,它会醒来,检查任务是否完成。如果是,则完成并返回。
接下来,如果任务在队列中但尚未启动,它会从队列中窃取工作并
在那里运行它,然后返回。
最后,如果队列正在运行但尚未完成,它会执行更复杂的操作。 (通常有效的最简单版本是它会阻塞任务,但这并不能解决一些病态情况)。无论如何,现在如果队列中的任务处于休眠状态,等待队列中尚未排队的另一个任务完成,我们仍然可以获得前进的进度。
我们不计算它们,而是存储共享的 future 以及其中的计算步骤。现在任何需要它们的人都只需做一个
.get()
。如果已经计算过该值,则得到该值;否则,我们计算它,然后得到它。后来,我们添加一个系统来在空闲或另一个线程中执行一些工作。这些在某些情况下取代了所说的延迟惰性期货,但在其他情况下则不然。
wait
。
effective modern c++
规则35
Compared to thread-based programming, a task-based design spares you the travails
of manual thread management
这意味着 std::launch::deferred 是一种更糟糕的情况,当操作系统无法为您分配新线程时,baz
函数仍然可以工作,但它作为延迟任务运行,而不是像
pthread_create
那样返回失败或像这样使用 std::thread 抛出异常:
terminate called after throwing an instance of 'std::system_error'
what(): Resource temporarily unavailable
结论:
// same thread with called.
std::async(std::launch::deferred, bax,..) = baz()
// create a new thread to run baz(..) in case of OS have ability to allocate a new thread, otherwise same above
std::async(baz, ...) = std::async(std::launch::deferred| std::launch::async , baz, ...) != baz() ;
https://man7.org/linux/man-pages/man3/pthread_create.3p.html
在
https://godbolt.org/z/hYv7TW51q进行了测试
假设您想限制进程上的线程数。使用
async
标志启动多个异步作业将使您失去可能拥有的任何控制权。有时这是可以的,但有时却不是。但是使用
deffered
,您可以在主线程上启动一些任务,并在您控制的工作线程上,您可以调用
get()
来确定性地运行任务。