考虑以下两段代码,我尝试启动10000个线程:
Snippet 1
std::array<std::future<void>, 10000> furArr_;
try
{
size_t index = 0;
for (auto & fut : furArr_)
{
std::cout << "Created thread # " << index++ << std::endl;
fut = std::async(std::launch::async, fun);
}
}
catch (std::system_error & ex)
{
std::string str = ex.what();
std::cout << "Caught : " << str.c_str() << std::endl;
}
// I will call get afterwards, still 10000 threads should be active by now assuming "fun" is time consuming
Snippet 2
std::array<std::thread, 10000> threadArr;
try
{
size_t index = 0;
for (auto & thr : threadArr)
{
std::cout << "Created thread # " << index++ << std::endl;
thr = std::thread(fun);
}
}
catch (std::system_error & ex)
{
std::string str = ex.what();
std::cout << "Caught : " << str.c_str() << std::endl;
}
第一种情况总是成功.i.e。我能够创建10000个线程,然后我必须等待所有这些线程完成。在第二种情况下,几乎总是在创建1600+个线程后我最终得到一个异常(“资源不可用再试一次”)。
使用std :: launch :: async的启动策略,我认为这两个代码段的行为应该相同。与async的启动策略不同的std :: async是如何使用std :: thread显式启动线程的?
我在Windows 10,VS2015上,二进制是在x86发布模式下构建的。
答案 0 :(得分:1)
首先,感谢Igor Tandetnik给我这个答案的指示。
当我们使用std :: async(使用异步启动策略)时,我们会说“
“我希望在单独的线程上完成这项工作”。
当我们使用std :: thread时,我们说
“我希望在新线程上完成这项工作”。
细微差别意味着使用线程池实现异步(通常)。这意味着如果我们多次使用异步调用方法,通常该方法中的线程ID将重复,即异步将多个作业分配给池中的同一组线程。而对于std :: thread,它永远不会。
这种差异意味着显式启动线程可能比使用异步启动策略使用异步更具资源密集性(因此也是异常)。