edulcorantという単語の使用のポイント。:)
サンプルコードの問題は、すべてをタスクにパッケージ化することですが、それらのタスクの実行をスケジュールすることはありません。
int calculate_the_answer_to_life() { ... }
int calculate_the_answer_to_death() { ... }
std::packaged_task<int()> pt(calculate_the_answer_to_life);
std::future<int> fi = pt.get_future();
std::packaged_task<int()> pt2(calculate_the_answer_to_death);
std::future<int> fi2 = pt2.get_future();
int calculate_barzoom(std::future<int>& a, std::future<int>& b)
{
boost::wait_for_all(a, b);
return a.get() + b.get();
}
std::packaged_task<int()> pt_composite([]{ return calculate_barzoom(fi, fi2); });
std::future<int> fi_composite = pt_composite.get_future();
この時点で私が書くなら
pt_composite();
int result = fi_composite.get();
私のプログラムは永久にブロックされます。pt_composite
でブロックされcalculate_barzoom
、でブロックされwait_for_all
、でブロックされ、両方でブロックさfi
れるため、完了しか、それぞれfi2
実行するまで完了しませんそして、私のプログラムがブロックされているので、誰もそれらを実行することはありません!pt
pt2
あなたはおそらく私がこのようなものを書くことを意味しました:
std::async(pt);
std::async(pt2);
std::async(pt_composite);
int result = fi_composite.get();
これは機能します。ただし、これは非常に非効率的async
です。2つのスレッドに相当する作業を実行するために、(への3つの呼び出しを介して)3つのワーカースレッドを生成します。その3番目のスレッド(実行中のスレッド)pt_composite
はすぐに生成され、実行が終了するまでスリープpt
状態になります。pt2
これは回転するよりはましですが、存在しないよりもかなり悪いです。つまり、スレッドプールのワーカーが本来あるべき数よりも1つ少ないということです。CPUコアごとに1つのスレッドしかなく、常に多くのタスクが発生するもっともらしいスレッドプールの実装では、これは、1つのCPUコアがアイドル状態になっていることを意味します。そのコアで実行されることは、現在、内部でブロックされていwait_for_all
ます。
私たちがやりたいのは、私たちの意図を宣言的に宣言することです。
int calculate_the_answer_to_life() { ... }
int calculate_the_answer_to_death() { ... }
std::future<int> fi = std::async(calculate_the_answer_to_life);
std::future<int> fi2 = std::async(calculate_the_answer_to_death);
std::future<int> fi_composite = std::when_all(fi, fi2).then([](auto a, auto b) {
assert(a.is_ready() && b.is_ready());
return a.get() + b.get();
});
int result = fi_composite.get();
次に、ライブラリとスケジューラを連携させて、正しいことを実行します。タスクをすぐに続行できないワーカースレッドを生成しないでください。エンドユーザーが明示的にスリープ、待機、またはブロックするコードを1行でも記述しなければならない場合、パフォーマンスの一部が確実に失われます。
言い換えると、その時間の前にワーカースレッドを生成しません。
明らかに、ライブラリのサポートなしで、これらすべてを標準のC++で実行することは可能です。これがライブラリ自体の実装方法です。しかし、最初から実装するのは非常に苦痛であり、多くの微妙な落とし穴があります。そのため、ライブラリのサポートが間もなく開始されるのは良いことです。
Roshan Shariffの回答で言及されているISO提案N3428はN3857として更新され、N3865はさらに便利な機能を提供します。