packaged_taskとasyncの違いは何ですか?質問する

packaged_taskとasyncの違いは何ですか?質問する

C++11のスレッドモデルを使っているときに、

std::packaged_task<int(int,int)> task([](int a, int b) { return a + b; });
auto f = task.get_future();
task(2,3);
std::cout << f.get() << '\n';

そして

auto f = std::async(std::launch::async, 
    [](int a, int b) { return a + b; }, 2, 3);
std::cout << f.get() << '\n';

まったく同じことを行うようです。std::asyncを実行した場合、大きな違いが生じる可能性があることは理解していますstd::launch::deferredが、この場合、違いはありますか?

これら 2 つのアプローチの違いは何ですか? さらに重要なのは、どのようなユースケースでどちらを使用すべきですか?

ベストアンサー1

実際、先ほど挙げた例は、次のようなかなり長い関数を使った場合の違いを示しています。

//! sleeps for one second and returns 1
auto sleep = [](){
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return 1;
};

パッケージ化されたタスク

A はpackaged_task自動的には起動しないので、呼び出す必要があります。

std::packaged_task<int()> task(sleep);

auto f = task.get_future();
task(); // invoke the function

// You have to wait until task returns. Since task calls sleep
// you will have to wait at least 1 second.
std::cout << "You can see this after 1 second\n";

// However, f.get() will be available, since task has already finished.
std::cout << f.get() << std::endl;

std::async

一方、std::asyncwith はlaunch::async別のスレッドでタスクを実行しようとします。

auto f = std::async(std::launch::async, sleep);
std::cout << "You can see this immediately!\n";

// However, the value of the future will be available after sleep has finished
// so f.get() can block up to 1 second.
std::cout << f.get() << "This will be shown after a second!\n";

欠点

しかし、あらゆるものに使用しようとする前にasync、返される future には特別な共有状態があり、次のfuture::~futureブロックが必要であることに留意してください。

std::async(do_work1); // ~future blocks
std::async(do_work2); // ~future blocks

/* output: (assuming that do_work* log their progress)
    do_work1() started;
    do_work1() stopped;
    do_work2() started;
    do_work2() stopped;
*/

したがって、本当に非同期にしたい場合は、返された を保持する必要がありますfuture。または、状況が変わっても結果を気にしない場合は、次のようにします。

{
    auto pizza = std::async(get_pizza);
    /* ... */
    if(need_to_go)
        return;          // ~future will block
    else
       eat(pizza.get());
}   

詳細については、ハーブ・サッターの記事をご覧ください。asyncそして~future、そしてスコット・マイヤーのstd::futures特別でstd::asyncはない、洞察を説明しています。また、この動作には注意してくださいC++14以降で規定されたですが、C++11 でも一般的に実装されています。

さらなる違い

を使用すると、std::async特定のスレッドでタスクを実行できなくなり、std::packaged_task他のスレッドに移動できるようになります。

std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::thread myThread(std::move(task),2,3);

std::cout << f.get() << "\n";

また、packaged_taskを呼び出す前に を呼び出す必要がありますf.get()。そうしないと、future が準備完了にならないため、プログラムがフリーズしてしまいます。

std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n"; // oops!
task(2,3);

要約

std::async何かを完了させたいが、いつ完了するかは気にしない、std::packaged_taskあるいは他のスレッドに移動したり後で呼び出したりするために物事をまとめたい場合に使用します。または、引用するとキリスト教徒:

結局のところ、std::packaged_taskは を実装するための低レベルの機能にすぎませんstd::async(そのため、std::asyncなどの他の低レベルの機能と一緒に使用すると、よりも多くのことが可能になりますstd::thread)。簡単に言えば、は にリンクされた でstd::packaged_taskあり、をラップして呼び出します(おそらく別のスレッドで)。std::functionstd::futurestd::asyncstd::packaged_task

おすすめ記事