C ++编译器如何在std :: async的延迟和异步执行之间进行选择?

时间:2017-09-07 17:35:56

标签: c++ c++11 asynchronous

似乎std::async的默认行为非常有利于std::launch::deferred。我试图理解为什么默认行为似乎永远不会实际产生异步任务。请考虑以下代码:

#include <iostream>
#include <future>
#include <thread>
#include <chrono>
#include <vector>


int main(void)
{
    std::vector<std::future<void>> task_list;

    size_t n_tasks = 10; // Let's say this could change at runtime
    // The first two seem interchangeable in this example:
    //auto launch_pol = std::launch::deferred;
    //auto launch_pol = std::launch::async | std::launch::deferred;
    // Only this seems to actually do async tasks:
    auto launch_pol = std::launch::async;

    auto start_time = std::chrono::steady_clock::now();

    // Generate a bunch of tasks
    for (size_t i = 0; i < n_tasks; i++) {
        task_list.emplace_back(std::async(launch_pol,
            [i](){
                std::cout << " Starting task " << i << std::endl;
                // The sleep is emulating, for example, a slow, I/O
                // bound operation
                std::this_thread::sleep_for(std::chrono::seconds(1));
                std::cout << " Stopping task " << i << std::endl;
            }
        ));
        // The following lines are experiments I tried to nudge the
        // task to start doing something.
        if (!task_list.at(i).valid()) {
            std::cout << "Task not valid!" << std::endl;
        }
        task_list.at(i).wait_for(std::chrono::milliseconds(1));
    }


    // Wait for them to complete
    for (auto& task : task_list) {
        task.get();
    }

    std::chrono::duration<double> stop_time =
        std::chrono::steady_clock::now() - start_time;
    std::cout << "Execution time: " << stop_time.count() << std::endl;

    return 0;
}

请注意,我一直在试验多个启动策略。似乎除非我明确地陈述std::launch::async(仅!),否则编译器将回退到std::launch::deferred。我尝试使用Clang 3.8,gcc 5.4,而this post似乎表明MSVC以相同的方式工作。

好的,这与C ++标准并不矛盾。我知道这不是一个bug。如果我们指定deferred,我们可能会得到延迟评估,这(在这种情况下)与我的任务的串行执行几乎相同。但是,如果编译器只回到std::launch::deferred

,那又有什么意义呢?

如果编译器总是回退到懒惰评估,那么在没有std::async的情况下调用std::launch::async似乎毫无意义。如果我使用默认的启动策略,我希望C ++运行时在启动线程时是否聪明。

一些背景:在我试图解决的问题中,我正在运行可变数量的初始化调用,这些调用非常慢,但完全受I / O限制(即,它们大部分时间等待结果来自别处)。这些数量可能会扩展,所以我希望从编译器的一些帮助来安排线程。

1 个答案:

答案 0 :(得分:2)

编译器供应商基本上都选择了#34;选择一个&#34;意思是&#34;延期&#34;。

这很糟糕。

他们可以自由选择任何逻辑。他们选择让他们的逻辑“始终推迟”。