web-dev-qa-db-ja.com

非同期で、GUIベースの非同期プログラミング専用ですか?

私はC#の新しいasyncおよびawait演算子について読んでいて、どのような状況でそれらが私に役立つ可能性があるかを理解しようとしました。私はいくつかのMSDNの記事を研究しましたが、これが行間で読んだものです。

WindowsフォームとWPFイベントハンドラーにはasyncを使用できるため、操作の大部分が実行されている間、UIスレッドをブロックすることなく長いタスクを実行できます。

_async void button1_Click(object sender, EventArgs e)
{
    // even though this call takes a while, the UI thread will not block
    // while it is executing, therefore allowing further event handlers to
    // be invoked.
    await SomeLengthyOperationAsync();
}
_

awaitを使用するメソッドはasyncである必要があります。つまり、コード内のどこかでasync関数を使用すると、最終的には呼び出しシーケンスのすべてのメソッドがUIイベントハンドラーから強制されます。最下位レベルのasyncメソッドもasyncになるまで。

つまり、通常の古き良きThreadStartエントリポイント(または古き良きstatic int Main(string[] args)のコンソールアプリケーション)でスレッドを作成する場合、asyncとを使用することはできません。 awaitある時点でawaitを使用し、それを使用するメソッドをasyncにする必要があるため、呼び出し元のメソッドでもawaitそしてそれをasyncなどにします。ただし、スレッドのエントリポイント(またはMain())に到達すると、awaitが制御を譲る呼び出し元はありません。

したがって、基本的には、標準のWinFormsとWPFメッセージループを使用するGUIがないと、asyncawaitを使用できません。 MSDNは、asyncプログラミングはマルチスレッドを意味するのではなく、代わりにUIスレッドの空き時間を使用すると述べているので、それはすべて理にかなっていると思います。コンソールアプリケーションまたはユーザー定義のエントリポイントを持つスレッドを使用する場合、非同期操作を実行するにはマルチスレッドが必要になります(互換性のあるメッセージループを使用しない場合)。

私の質問は、これらの仮定は正確ですか?

36
dialer

したがって、基本的に、標準のWinFormsとWPFメッセージループを使用するGUIがないと、非同期を使用して待機することはできません。

それは絶対にないの場合です。

WindowsフォームとWPFでは、async/awaitには、待機していた非同期操作が完了したときにUIスレッドに戻るという便利なプロパティがありますが、それが唯一の目的であるとは限りません。それに。

非同期メソッドがスレッドプールスレッドで実行される場合-例: Webサービスでは、継続(非同期メソッドの残りの部分)は、コンテキスト(セキュリティなど)が適切に保持された状態で、anyスレッドプールスレッドで実行されます。これは、スレッドの数を抑えるのに非常に役立ちます。

たとえば、トラフィックの多いWebサービスがあり、そのほとんどが他のWebサービスにリクエストをプロキシしているとします。ネットワークトラフィックによるものであれ、別のサービス(データベースなど)での本物の時間によるものであれ、ほとんどの時間を他のことを待つことに費やしています。そのために多くのスレッドは必要ありませんが、呼び出しをブロックすると、当然、リクエストごとにスレッドが作成されます。 async/awaitを使用すると、スレッドが非常に少なくなります。これは、リクエストがlotであっても、ある時点で実際に実行する必要のあるリクエストが非常に少ないためです。飛行中」。

問題は、async/awaitがUIコードで最も簡単にできることですデモンストレーションバックグラウンドスレッドを適切に使用するか、UIスレッドで多くの作業を行うことの苦痛を誰もが知っているからです。それは、機能が役立つ唯一の場所であるという意味ではありません-それから遠く離れています。

さまざまなサーバーサイドテクノロジ(MVCやWCFなど)はすでに非同期メソッドをサポートしており、他のテクノロジもそれに続くことを期待しています。

28
Jon Skeet

Awaitを使用するメソッドは非同期である必要があります。つまり、コード内のどこかで非同期関数を使用すると、UIイベントハンドラーから最下位レベルの非同期メソッドまでの呼び出しシーケンスのすべてのメソッドも非同期になります。

Trueではありません-asyncとマークされたメソッドは、awaitを使用できることを意味しますが、これらのメソッドの呼び出し元には制限がありません。メソッドがTaskまたは_Task<T>_を返す場合、それらはContinueWithまたは4.0のタスクで実行できる他のすべてを使用できます。

UI以外の良い例は、MVC4AsyncControllerです。

最終的に、async/awaitは主にコンパイラーの書き換えを目的としているため、同期コードのように見えるものを記述し、async/awaitが追加される前に必要だったすべてのコールバックを回避できます。また、SynchronizationContextの処理にも役立ち、スレッドアフィニティ(UIフレームワーク、ASP.NET)のあるシナリオに役立ちますが、それらがなくても引き続き役立ちます。たとえば、Mainは常にDoStuffAsync().Wait();を実行できます。 :)

8
James Manning

私の質問は、これらの仮定は正確ですか?

番号。

WindowsフォームとWPFイベントハンドラーに非同期を使用できるため、操作の大部分が実行されている間、UIスレッドをブロックすることなく長いタスクを実行できます。

本当。 SilverlightやWindowsStoreなどの他のUIアプリケーションにも当てはまります。

また、alsoはASP.NETにも当てはまります。この場合、ブロックされないのはHTTPリクエストスレッドです。

Awaitを使用するメソッドは非同期である必要があります。つまり、コード内のどこかで非同期関数を使用すると、UIイベントハンドラーから最下位レベルの非同期メソッドまでの呼び出しシーケンスのすべてのメソッドも非同期になります。

これはベストプラクティスですが( "asyncずっと下に")、厳密には必須ではありません。非同期操作の結果をcanブロックします。多くの人がコンソールアプリケーションでこれを行うことを選択します。

通常の古き良きThreadStartエントリポイント

えーと…「普通の古き良き」を問題にしなければなりません。私のブログで説明しているように、 Threadは、バックグラウンド操作を行うための最悪のオプションです

私の asyncawait の紹介を確認し、 async/awaitをフォローアップすることをお勧めしますFAQ

6
Stephen Cleary
  1. async-awaitは、タスククラス操作のラッパーのみであり、その名前が付けられたTasks Parallel Library-TPL(async-await自動コード生成技術の前に公開されています)の一部です。
  2. したがって、実際には、async内でUIコントロールへの参照を使用することはできません-待機します。
  3. 通常、async-awaitは、Webとサーバーの関係、リソースのロード、SQLのための強力なツールです。それは生きているUIでスマートな待機データで動作します。
  4. 通常、TPLアプリケーション:単純な大きなサイズのループから、共有データに基づく複雑な計算での多段階の並列計算まで(ContinueWithなど)
0
Sergey Orlov