実際、先ほどの例は、次のようなかなり長い関数を使用した場合の違いを示しています。
//! 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::async
with 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
ください。
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()
。そうしないと、将来の準備ができなくなるため、プログラムがフリーズします。
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n"; // oops!
task(2,3);
TL; DR
使用std::async
あなたには、いくつかの物事が行われ、それが完了したら、本当に気にしない、としたい場合はstd::packaged_task
、あなたが他のスレッドに移動するか、後でそれらを呼び出すために物事をラップする場合。または、クリスチャンを引用するには:
結局のところ、a std::packaged_task
は実装するための下位レベルの機能にすぎstd::async
ません(そのためstd::async
、などの他の下位レベルのものと一緒に使用した場合よりも多くの機能を実行できますstd::thread
)。単に話されたa std::packaged_task
はaにstd::function
リンクされてstd::future
おりstd::async
、std::packaged_task
(おそらく別のスレッドで)a をラップして呼び出します。