考虑以下两个代码片段,我正在尝试启动 10000 个线程:
片段 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
片段 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;
}
第一种情况总是成功的,即我能够创建 10000 个线程,然后我必须等待所有线程完成。在第二种情况下,几乎总是在创建 1600+ 线程后最终出现异常("资源不可用重试"(。
使用std::launch::async的启动策略,我认为这两个代码段的行为方式应该相同。具有异步启动策略的 std::async 与使用 std::thread 显式启动线程有何不同?
我在Windows 10,VS2015上,二进制是在x86发布模式下构建的。
首先,感谢Igor Tandetnik为我提供了这个答案的方向。
当我们使用 std::async
(带有异步启动策略(时,我们说:
"我想在单独的线程上完成这项工作"。
当我们使用std::thread
时,我们说:
"我想在新线程上完成这项工作"。
细微的区别意味着async
(通常(使用线程池实现。这意味着如果我们多次使用 async
调用一个方法,通常该方法中的线程 id 会重复,即 async
将多个作业分配给池中的同一组线程。而对于std::thread
,它永远不会。
这种差异意味着显式启动线程可能比将async
与async
启动策略一起使用更占用资源(因此例外(。