品比三家:C++のtask based同時
3871 ワード
前の記事で述べたように、私は文章を書いて、話をするつもりです
TL;DRasync:最高レベルの抽象を提供する.スレッドの実行タイミングを制御する必要がない場合は、これを選択します. packaged_task:抽象階層比 promise:抽象階層が最も低い.スレッドにターゲット結果の値を設定したい場合は、これを選択します.
もっと詳しく知りたいなら、下を見続けましょう.
同局競技
次のコードでは、同じ機能をそれぞれこの3つで実現します.遅延2秒後に0を返します.
上記のコードから、この3つはそれぞれ異なる抽象階層で動作していることがわかります.
では、私たちの最初の結論は明らかです.
では、「場合によっては」とは何でしょうか.
async VS. packaged_task and promise
前述したように、
それでも、関数を実行するタイミングとfutureオブジェクトを取得するタイミングを分離したい場合は、
BTW,
このような予想外の行為はC++14でキャンセルされる.だからあなたが使っているコンパイラはこの問題に遭遇しないかもしれません.
packaged_task VS. promise
残りの2つの中でどうやって選びますか?
async
・packaged_task
とpromise
の違い.だから今私は穴を埋めに来ました.TL;DR
async
低.スレッドの実行タイミングを制御し、スレッドの実行結果であるターゲット結果を制御する必要がある場合は、これを選択します.もっと詳しく知りたいなら、下を見続けましょう.
同局競技
async
・packaged_task
とpromise
の3つに共通点があります.いずれも1つのfuture
オブジェクトを返すことができ、ユーザーはこのfuture
のget
方法で最終的な結果を得ることができます.次のコードでは、同じ機能をそれぞれこの3つで実現します.遅延2秒後に0を返します.
#include
#include
#include
#include
int main()
{
std::packaged_task task([](){
std::chrono::milliseconds dura( 2000 );
std::this_thread::sleep_for( dura );
return 0;
});
std::future f1 = task.get_future();
std::thread(std::move(task)).detach();
std::future f2 = std::async(std::launch::async, [](){
std::chrono::milliseconds dura( 2000 );
std::this_thread::sleep_for( dura );
return 0;
});
std::promise p;
std::future f3 = p.get_future();
std::thread([](std::promise p){
std::chrono::milliseconds dura( 2000 );
std::this_thread::sleep_for( dura );
p.set_value(0);
},
std::move(p)).detach();
std::cout << "Waiting..." << std::flush;
f1.wait();
f2.wait();
f3.wait();
std::cout << "Done!
Results are: "
<< f1.get() << " " << f2.get() << " " << f3.get() << "
";
return 0;
}
上記のコードから、この3つはそれぞれ異なる抽象階層で動作していることがわかります.
async
階層が最も高く、関数を1つ提供するだけで、future
オブジェクトが返されます.次は結果を待つだけです.packaged_task
その次に、あなたはpackaged_task
を作成した後に、thread
を作成し、packaged_task
それを実行します.promise
最低です.thread
を作成した後、対応するpromise
をパラメータとして入力します.まだ終わっていないので、関数に手動でpromise
の値を設定するのを忘れないでください.では、私たちの最初の結論は明らかです.
async
抽象レベルが最も高いので、同時プロセスを細かく制御する必要がない限り(例えば、場合によっては)、優先的にasync
非同期タスクを実行します.では、「場合によっては」とは何でしょうか.
async VS. packaged_task and promise
前述したように、
async
関数を受信して、future
を返します.デフォルトでは、関数はその場で実行されます.これはあなたが望んでいるものではないかもしれません.転送std::launch::defer
により、呼び出しfuture.get
実行開始async
の関数に変更できます.それでも、関数を実行するタイミングとfutureオブジェクトを取得するタイミングを分離したい場合は、
async
ではなく、より下位のpackaged_task
とpromise
を使用することが望ましい.BTW,
async
変な特性があり、async
戻るfuture
一時変数(またはその戻り値にかかわらず)に値を付与すると、その変数のライフサイクルが終了するまでプログラムはブロックされ、async
の関数が完了するまでブロックされます.{
std::future tmp = std::async(std::launch::async, [](){
std::chrono::milliseconds dura(VERY_LONG_TIME);
std::this_thread::sleep_for(dura);
return 0;
});
// block here for VERY_LONG_TIME
}
このような予想外の行為はC++14でキャンセルされる.だからあなたが使っているコンパイラはこの問題に遭遇しないかもしれません.
packaged_task VS. promise
残りの2つの中でどうやって選びますか?
promise
の階層比packaged_task
低いのでpromise
ユーザへの制御粒度もpackaged_task
より細い.だから、もっと徹底的にコントロールしたいならpromise
を選びましょう.promise
ほぼfuture
の半分.対promise
呼び出しset_value
対future
呼び出しset_value
.packaged_task
よりもpromise
関数の戻り値は気にならない――あくまでその値は手動で呼び出す必要があるset_value
設定する.