9

複雑な計算アルゴリズムを構築しました。完了までにかなりの時間がかかります。また、アプリケーションが確実に応答するようにする必要があります。職業はなんですか?

  • A. async / awaitを使用してください。
  • B.コードを同期的に実行します。
  • C. Task.Runを使用してください。
  • D. BackgroundWorkerを使用する。

答えはCです。しかし、A)が間違っている理由を誰かが説明できますか?なぜなら、複雑なアルゴリズムはCPUに依存しているということではありません。 CPUバウンドの場合は、タスクを使用する必要があります(タスクは、完了するまで現在のスレッドを中断させるのに役立ちますが、あまりよく理解されていない理由です)。さらに、async / awaitを使用するタイミングを決定し、タスクを使用する方法を説明してください。


  • 偽の二分法。答えはAとCの両方です。ASP.NETでは、答えはBです。 - Stephen Cleary

3 답변


3

職業はなんですか?

A. async / awaitを使用してください。

B.コードを同期的に実行します。

C. Task.Runを使用してください。

D. BackgroundWorkerを使用する。

async/awaitC#5.0の機能は、同期コードを書くのと同じくらい簡単に非同期コードを作るために実装されました。 WinAPIを調べると、ほぼすべての非同期エンドポイントが完全非同期APIを公開していることがわかります。スレッドはありません。さらに調べると、同じエンドポイントが実行していることに気付くでしょう。入出力制限オペレーション。

あなたのアルゴリズムがCPUバウンドそして、複数のプロセッサに渡って効果的な計算を可能にする方法で書かれている場合(例えば、あなたのアルゴリズムは同期を必要とする共有状態を持たない)、タスク並列ライブラリ.NET 4.0で導入されました。 TPLはThreadPoolを抽象化したもので、マルチプロセッサ環境で作業を均等にオフロードしようとします。

awaitキーワードはどのキーワードでも使用できます待つオブジェクト、つまりオブジェクトがGetAwaiter方法。使いたいawaitawaitableを使用していて、そのwaitwaitが作業を終えたときに実行を再開したいとき。 ATaskawaitableパターンを実装し、将来完成する予定の作業単位を記述するために使用されます。あなたが使用することができますTask.Runそしてawaitワーカースレッドで作業単位をオフロードしたいときに、その作業が完了するまで呼び出し側のメソッドに制御を戻す

複数のプロセッサにまたがってCPUバウンドの作業をディスパッチするもう1つの方法は、Parallel公開するクラスParallel.ForそしてParallel.ForEach

ちなみに、BackgroundWorkerバックグラウンドスレッドの作業をオフロードするために使用することもできます(質問をした人がその後に行ったことがそれである場合)。それはおすすめ.NET 4.0がリリースされてからTPLを使用する方法

結論として、タスク並列ライブラリを使用することはバックグラウンドスレッドに作業をオフロードするための推奨される方法です。あなたはそれらと組み合わせてそれらを使用することができますParallelあなたのアルゴリズムの並列性を最大にするためのライブラリ。そうした後、コードをテストするマルチスレッドを使用するオーバーヘッドがalgoを同期的に実行するのにかかる時間を超えないようにするためです。

編集する

Stephanがコメントで述べたように、あなたは両方を組み合わせることができますParallel.ForEachそしてTask.Runバックグラウンドスレッド内で並列ループをオフロードするには

var task = Task.Run(() => Parallel.ForEach(.. //Loop here));


  • アプローチを組み合わせることも役に立ちます。await Task.Run(() => Parallel.ForEach(...))UIが非同期的に扱うバックグラウンドスレッドに対して並列処理を行います。 - Stephen Cleary

2

私は、「計算」が他の情報がない場合にはCPUバウンドアルゴリズムを意味すると思います。アルゴリズムがIOに制限されている場合、async / awaitは許容できるだけでなく、正しい答えです。


  • それは本当です。もちろん、あなたはDispatcherアプローチに行くことができます。 - Stilgar
  • @DimitarDimitrov(使用している場合)Task.Run渡されたデリゲートは、UIスレッド以外のスレッドで実行される可能性があります。あなたのUIは反応し続けるでしょう次の方法でタスクの完了をブロックしない場合はWait()またはResult。タスクの完了を処理し、呼び出したスレッドと通信する方法Task.Runしかし、そもそも、あなた次第です。awaitまたは、適切なタスク継続を使用してタスク継続を使用できます。TaskSchedulerまたは、元のSynchronizationContextを明示的にキャプチャして、デリゲート内からそれにポストバックすることもできます。 - Kirill Shlenskiy
  • (続き)または使用できますDispatcher.InvokeまたはControl.Invokeまたは、独自のAsyncEnumeratorをロールバックすることもできます(blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx)私のポイントは、それを実行するには約100万の方法があり、そしてasync/awaitたとえそれが皆の頭に浮かぶ最初のことであっても、たまたまそれらのうちの1つである(それは全く理解できる) - Kirill Shlenskiy
  • @ KirillShlenskiy確かに、あなたは100%正しいです、私は同意します(あなたが少し不愉快であるにもかかわらず)、しかし質問がゴミであるという事実はまだ残っています(私見)。 - Dimitar Dimitrov
  • @DimitarDimitrov、同意した。 - Kirill Shlenskiy

1

私は質問があなたが同期的にプログラムされたアルゴリズムを持っていると仮定すると信じます。質問は、それがCPUバウンドであることを漠然と暗示している「計算」であると述べています。それはまたアルゴリズムが同期的に書かれていることを非常に漠然と暗示しています。例えば:

public int CalculateStuff() {
     ....
}

私が検討することは、このメソッドに非同期のものを作成することです。

public async Task<int> CalculateStuffAsync() {
      return await Task.Run(() => CalculateStuff());
}

それからあなたのユーザーインターフェースで:

LoadingIndicator.IsEnabled = true;
ResultTextBox.Text = await CalculateStuffAsync();
LoadingIndicator.IsEnabled = false;

それゆえ、正しい答えはおそらくAとCの両方でしょう。いずれにせよ、質問はあまりに曖昧すぎていかなる結論も引き出すことができません。


  • @DimitarDimitrovは同意する。Bを除くすべてが技術的に有効である - Bas
  • @BasBrekelmans、公開サービスxxxAsyncCPUバウンドの作業のためのラッパーはデザインが良くありません。呼び出し元がラップできないようなものではありませんCalculateStuffTask.Run必要ならば。次のことも考慮してください。CalculateStuffAsync().Wait()。なしConfigureAwait(false)あなたが書いたまでそこになかったデッドロックバグを導入したばかりですasyncほとんどゼロの利益のための方法。 - Kirill Shlenskiy
  • @DimitarDimitrov、言わないでください。 null以外をインストールするアプリケーションでコードを少し実行します。SynchronizationContext(つまりWindows Forms / WPF)そして何が起こるか見てください。これはあなたのawaitオリジナルに移行する必要がありますSynchronizationContext非同期操作の結果が返される前に。次の方法でスレッドをブロックした場合Task.Waitスレッドがタスクの待機中にビジーになるため(このタスクは完了しません)、この遷移は発生しません。チェックメイト取り出すasync/awaitタスクを直接返すだけで解決しました。 - Kirill Shlenskiy
  • (または使用ConfigureAwait(false)明らかに) - Kirill Shlenskiy
  • @DimitarDimitrov、問題ありません。そして、私の返事を誤って申し上げたことに対する私の謝罪を受け入れてください。私が書いたとき、私はあなたをBas Brekelmansと混同しました。 - Kirill Shlenskiy

関連する質問

最近の質問