std::async 函数 运行 连续

std::async function running serially

当在 for 循环中使用 std::async 和 launch::async 时,我的代码在同一个线程中连续运行,就好像每个异步调用在启动之前等待前一个。在 std::async 引用 (std::async) 的注释中,如果 std::future 未绑定到引用,这是可能的,但我的代码不是这种情况。任何人都可以弄清楚为什么它是 运行 连续吗?

这是我的代码片段:

class __DownloadItem__ { //DownloadItem is just a "typedef shared_ptr<__DownloadItem__> DownloadItem"
    std::string buffer;
    time_t last_access;
 std::shared_future<std::string> future;
}

for(uint64_t start: chunksToDownload){
        DownloadItem cache = std::make_shared<__DownloadItem__>();
        cache->last_access = time(NULL);
        cache->future =
                std::async(std::launch::async, &FileIO::download, this, api,cache, cacheName, start, start + BLOCK_DOWNLOAD_SIZE - 1);
     }
}

未来存储在共享未来中,因为多个线程可能正在等待同一个未来。

我也是用GCC 6.2.1编译的

这是 C++11 定义的 std::async 的错误特征。它的期货析构函数是特殊的,等待操作完成。有关 Scott's Meyers 博客的更多详细信息。

cache 在每次循环迭代结束时被销毁,从而调用其子对象的析构函数。

使用 packaged_task 或确保您保留指向 cache 的共享指针副本的容器,以避免等待析构函数。就个人而言,我会选择 packeged_task

正如您自己注意到的,std::async 返回的 futurefuture d-tor 阻塞并等待异步操作完成(对于 future变成 ready)。 在您的情况下, cache 对象在每次循环迭代时都超出范围,因此与它所持有的 future 一起被破坏,因此您会看到上述效果。

析构函数中async块返回的std::future。这意味着当您到达

}
for(uint64_t start: chunksToDownload){
    DownloadItem cache = std::make_shared<__DownloadItem__>();
    cache->last_access = time(NULL);
    cache->future =
            std::async(std::launch::async, &FileIO::download, this, api,cache, cacheName, start, start + BLOCK_DOWNLOAD_SIZE - 1);
 }  // <-- When we get here

cache 被销毁,进而调用 future 的析构函数,等待线程完成。

您需要做的是将从 async 返回的每个 future 存储在一个单独的永久性 future 中,该 future 在 for 循环之外声明。