【问题标题】:c++11 threads vs asyncc++11 线程 vs 异步
【发布时间】:2017-06-22 02:24:37
【问题描述】:

考虑以下两个我尝试启动 10000 个线程的 sn-ps 代码:

片段 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 的启动策略,我认为两个 sn-ps 的行为方式应该相同。使用 async 启动策略的 std::async 与使用 std::thread 显式启动线程有何不同?

我在 Windows 10 VS2015 上,二进制是在 x86 发布模式下构建的。

【问题讨论】:

  • 片段 1 不会创建 10000 个线程。它创建了 10000 个工作单元,这些工作单元在系统维护的几个线程池中排队等待执行。有fun 打印std::this_thread::get_id(),自己看看。
  • 哇,好漂亮。我不知道!线程 ID 似乎确实重复了。所以潜在地使用异步就像拥有自己的线程池。这个比喻对吗?
  • 好吧,标准并没有具体说明如何实现std::async;但一个典型的实现实际上会使用一个线程池。

标签: multithreading c++11 stdthread stdasync


【解决方案1】:

首先,感谢Igor Tandetnik 给我这个答案的方向。

当我们使用std::async(带有异步启动策略)时,我们是在说:

“我想在单独的线程上完成这项工作”。

当我们使用std::thread 时,我们是在说:

“我想在新线程上完成这项工作”。

细微的差别意味着async(通常)使用线程池实现。这意味着如果我们多次使用async 调用一个方法,该方法中的线程ID 通常会重复,即async 将多个作业分配给池中的同一组线程。而对于std::thread,它永远不会。

这种差异意味着显式启动线程可能比使用 asyncasync 启动策略更占用资源(因此例外)。

【讨论】:

猜你喜欢
  • 2014-12-31
  • 2016-07-20
  • 1970-01-01
  • 2021-11-22
  • 2015-01-13
  • 1970-01-01
  • 1970-01-01
  • 2017-09-13
  • 2017-10-24
相关资源
最近更新 更多