web-dev-qa-db-ja.com

なぜstd :: asyncを使用する必要があるのですか?

Std :: asyncを使用してその定義を読んでいる間、新しいC++ 11標準のすべてのオプションを詳しく調べようとしていますが、少なくともgcc 4.8.1のLinuxでは2つのことがわかりました。

  • asyncと呼ばれていますが、基本的に非同期関数に関連付けられているfutureを呼び出す行で、実際には「シーケンシャルな振る舞い」を取得しましたfoo 、プログラムはfooの実行が完了するまでブロックします。
  • 他のライブラリとまったく同じ外部ライブラリに依存し、pthreadを使用する場合はstd::async pthreadが必要です。

この時点で、ファンクタの単純なセットよりもstd :: asyncを選択する理由を尋ねるのは自然です。それはまったくスケーリングさえしないソリューションであり、あなたが呼ぶ未来が多ければ多いほど、あなたのプログラムは反応しにくくなります。

私は何かが欠けていますか?非同期の非ブロッキングの方法で実行することが許可されている例を示してもらえますか?

62
user2485710

非同期操作の結果が必要な場合は、使用するライブラリに関係なくhaveをブロックします。アイデアは、いつブロックするかを選択できるようにすることです。できれば、すべての作業が既に完了しているため、ブロックする時間はごくわずかです。

std::asyncはポリシーで起動できますstd::launch::async または std::launch::deferred。指定しない場合、実装は選択が許可され、遅延評価を使用することを選択できます。これにより、将来から結果を取得しようとするときにすべての作業が行われ、ブロックが長くなります。したがって、作業が非同期的に行われるようにしたい場合は、std::launch::async

54
juanchopanza
  • 非同期と呼ばれますが、実際には「シーケンシャルな振る舞い」があります。

いいえ、std::launch::asyncポリシーを使用すると、新しいスレッドで非同期に実行されます。ポリシーを指定しない場合、might新しいスレッドで実行されます。

基本的に、非同期関数fooに関連付けられたfutureを呼び出す行で、プログラムはfooの実行が完了するまでブロックします。

Fooが完了していない場合のみブロックしますが、非同期に実行された場合(たとえば、std::launch::asyncポリシーを使用しているため)、必要になる前に完了した可能性があります。

  • 他のライブラリとまったく同じ外部ライブラリと、より優れた非ブロッキングソリューション、つまりpthreadに依存しています。つまり、std :: asyncを使用する場合はpthreadが必要です。

間違っていますが、Pthreadsを使用して実装する必要はありません(WindowsではConcRT機能を使用していません)。

この時点で、ファンクタの単純なセットよりもstd :: asyncを選択する理由を尋ねるのは自然です。

スレッドセーフを保証し、スレッド間で例外を伝播するためです。ファンクタの簡単なセットでそれを行うことができますか?

それはまったくスケーリングさえしないソリューションであり、あなたが呼ぶ未来が多ければ多いほど、あなたのプログラムは反応しにくくなります。

必ずしも。起動ポリシーを指定しない場合、スマート実装は、新しいスレッドを開始するか、遅延関数を返すか、より多くのリソースが利用可能になったときに後で決定する何かを返すかどうかを決定できます。

現在、GCCの実装では、起動ポリシーを提供しない場合、現在のリリースでは新しいスレッドで実行されません( bugzilla report があります)が、それはのプロパティですstd::async全般ではなく、その実装。標準の仕様と特定の実装を混同しないでください。 1つの標準ライブラリの実装を読むことは、C++ 11について学ぶには不十分な方法です。

非同期の非ブロッキングの方法で実行することが許可されている例を示してもらえますか?

これはブロックすべきではありません:

auto fut = std::async(std::launch::async, doSomethingThatTakesTenSeconds);
auto result1 = doSomethingThatTakesTwentySeconds();
auto result2 = fut.get();

起動ポリシーを指定することにより、非同期実行を強制します。実行中に他の作業を行うと、必要なときに結果が準備できます。

74
Jonathan Wakely

あなたの問題は_std::future_がgetでブロックしていると言っていることだと思います。ブロックするだけです結果がまだ準備できていない場合

結果の準備を整えることができれば、これは問題ではありません。

結果がすでに用意されていることを知る方法はたくさんあります。 futureをポーリングし、(比較的簡単に)尋ねることができます。ロックまたはアトミックデータを使用して準備ができているという事実を伝え、「完成した」futureアイテムを配信するフレームワークを構築できます。消費者が対話できるキューに、何らかの種類の信号を使用することができます(複数のことを一度にブロックするか、ポーリングするだけです)。

または、ローカルで実行できるすべての作業を終了し、リモート作業をブロックすることもできます。

例として、並列再帰マージソートを想像してください。配列を2つのチャンクに分割し、一方のチャンクでasyncソートを実行し、他方のチャンクをソートします。半分のソートが完了すると、元のスレッドは2番目のタスクが完了するまで進行できません。したがって、.get()とブロックを実行します。両方の半分がソートされると、マージを実行できます(理論的には、マージも少なくとも部分的に並行して実行できます)。

このタスクは、外部でやり取りする人にとっては線形タスクのように動作します。実行されると、配列がソートされます。

その後、これを_std::async_タスクでラップし、futureソートされた配列を作成できます。必要に応じて、シグナルプロシージャを追加してfutureが終了したことを通知できますが、シグナルを待機するスレッドがある場合にのみ意味があります。

参照http://en.cppreference.com/w/cpp/thread/async

Asyncフラグが設定されている場合(つまり、policy&std :: launch :: async!= 0)、asyncはstd :: thread(f、args ...)によって生成されるかのように、実行の別のスレッドで関数fを実行します。ただし、関数fが値を返すか、例外をスローする場合は、非同期が呼び出し元に返すstd :: futureを介してアクセス可能な共有状態で保存されます

スローされた例外の記録を保持するのは素晴らしいプロパティです。

3
fatihk

http://www.cplusplus.com/reference/future/async/

ポリシーには3つのタイプがあります。

  1. launch::async
  2. launch::deferred
  3. launch::async|launch::deferred

デフォルトでは、launch::async|launch::deferredstd::asyncに渡されます。

0