在使用C++ 11的线程模型时,我注意到了这一点
std::packaged_task<int(int,int)> task([](int a, int b) { return a + b; });
auto f = task.get_future();
task(2,3);
std::cout << f.get() << '\n';
Run Code Online (Sandbox Code Playgroud)
和
auto f = std::async(std::launch::async,
[](int a, int b) { return a + b; }, 2, 3);
std::cout << f.get() << '\n';
Run Code Online (Sandbox Code Playgroud)
似乎做了完全相同的事情.据我所知,有可能是一个重大的区别,如果我跑std::async带std::launch::deferred,但有一个在这种情况下?
这两种方法有什么区别,更重要的是,我应该使用哪种用例?
我正在尝试深入探索新C++ 11标准的所有选项,同时使用std :: async并阅读其定义,我注意到两件事,至少在linux下使用gcc 4.8.1:
pthread,如果你想使用std::async你需要pthread.在这一点上,我很自然地问为什么选择std :: async甚至是一组简单的仿函数?这是一个根本无法扩展的解决方案,您调用的未来越多,您的程序响应就越少.
我错过了什么吗?你能展示一个被授予以异步,非阻塞方式执行的例子吗?
任何人都可以高度直觉地知道何时使用它们?
参考文献:
高级别
我想在异步模式下调用一些没有返回值的函数而不等待它们完成.如果我使用std :: async,则在任务结束之前,未来的对象不会被破坏,这使得调用在我的情况下不同步.
例
void sendMail(const std::string& address, const std::string& message)
{
//sending the e-mail which takes some time...
}
myResonseType processRequest(args...)
{
//Do some processing and valuate the address and the message...
//Sending the e-mail async
auto f = std::async(std::launch::async, sendMail, address, message);
//returning the response ASAP to the client
return myResponseType;
} //<-- I'm stuck here until the async call finish to allow f to be destructed.
// gaining no benefit from the async call.
Run Code Online (Sandbox Code Playgroud)
我的问题是
使用std::async而不是手动创建std::thread对象的优点之一应该是std::async可以使用封面下的线程池来避免超额配置问题.但是哪些实现这样做?我的理解是微软的实现确实如此,但这些其他async实现呢?
boost::thread::async,不std::async)感谢您提供的任何信息.
VISUAL C++使用Windows线程池(Vista的CreateThreadpoolWork,如果可用,QueueUserWorkItem如果不)调用时std::async用std::launch::async.
池中的线程数是有限的.如果创建多个运行很长时间而没有休眠的任务(包括执行I/O),则队列中即将发生的任务将无法工作.
标准(我使用N4140)表示,借助std::async与std::launch::async
...调用
INVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...)(20.9.2,30.3.1.2),好像在一个新的执行线程中,由一个线程对象表示,并调用在DECAY_COPY()被调用的线程中进行求值async.
(§30.6.8p3,强调我的.)
std::thread的构造函数创建了一个新线程等.
关于一般的线程,它说(§1.10p3):
实现应确保所有未阻塞的线程最终取得进展.[ 注意:标准库函数可能会静默阻塞I/O或锁定.执行环境中的因素(包括外部强加的线程优先级)可能会阻止实现对前进进度做出某些保证.- 结束说明 ]
如果我创建了一堆OS线程或std::threads,都执行一些非常长(或许是无限)的任务,它们都将被安排(至少在Windows上;不会弄乱优先级,亲和力等).如果我们将相同的任务安排到Windows线程池(或使用std::async(std::launch::async, ...)哪个任务),则在先前的任务完成之前,后续计划的任务将不会运行.
严格来说,这是合法的吗?什么"最终"意味着什么?
问题是如果首先安排的任务事实上是无限的,那么剩下的任务就不会运行.所以其他线程(不是OS线程,但根据as-if规则的"C++ - 线程")将无法取得进展.
有人可能会争辩说,如果代码具有无限循环,则行为是不确定的,因此它是合法的.
但我认为,我们不需要标准所说的有问题的无限循环导致UB实现这一点.访问易失性对象,执行原子操作和同步操作都是"禁用"循环终止假设的副作用.
(我有一堆执行以下lambda的异步调用
auto lambda = [&] {
while (m.try_lock() == false) {
for (size_t i = 0; i < (2 << 24); i++) {
vi++;
}
vi = 0;
}
};
Run Code Online (Sandbox Code Playgroud)
并且只有在用户输入时才会释放锁定.但是还有其他有效的合法无限循环.)
如果我安排了几个这样的任务,我在他们之后安排的任务就无法运行. …
延迟未来背后的想法(仅通过std::async使用std::launch::deferredflag 调用实现)是仅当有人试图等待或拉动未来的未来价值或例外时才调用回调.到那时,回调没有被执行.
如果我将续约延迟到延期的未来,会发生什么std::future::then?延迟的未来将丢失(then使未来无效),而是返回新的未来.
在这种情况下,根据标准,会发生什么?新的未来是一个延期的未来吗?会不会陷入僵局?最新文档中未解决此问题.
C++标准的每个[futures.async]/3项目1,当一个函数与启动策略一起f传递时,将"运行"就像在新的执行线程中一样".std::asyncstd::launch::asyncf
鉴于它f可以做任何事情,包括无限循环和永久阻塞,一个实现如何提供在f自己的线程上运行而不实际在自己的线程上运行它的行为?也就是说,一个实现如何利用标准提供的"仿佛"摆动空间?
我已经多次被告知,我应该使用参数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;
}
Run Code Online (Sandbox Code Playgroud)
没有看中这里,包函子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 = …Run Code Online (Sandbox Code Playgroud) c++ ×10
stdasync ×10
c++11 ×8
asynchronous ×3
c++17 ×1
concurrency ×1
future ×1
std-future ×1
visual-c++ ×1