最速の学習のために..
メソッドの実行フローを理解する (図付き): 3 分
質問内省 (酒を学ぶ): 1 分
シンタックス シュガーをすばやく理解する: 5 分
開発者の混乱を共有する: 5 分
問題: 通常のコードの実際の実装を非同期コードにすばやく変更する: 2 分
次はどこへ?
メソッドの実行フローを理解する (図付き): 3 分
この画像では、#6 だけに注目してください (それ以上は何もありません)。

#6 ステップで、実行が不足して停止しました。続行するには、getStringTask(一種の関数) からの結果が必要です。したがって、await
オペレーターを使用して進行を中断し、呼び出し元 (このメソッドの) に制御を戻します (yield)。getStringTask への実際の呼び出しは、#2 の前半で行われました。#2 では、文字列の結果を返すという約束がなされました。しかし、いつ結果を返すのでしょうか? (#1:AccessTheWebAsync) もう一度 2 回目の呼び出しを行う必要がありますか? #2(calling statement) と #6(awaiting statement) のどちらが結果を取得しますか?
AccessTheWebAsync() の外部呼び出し元も待機中です。したがって、呼び出し側は AccessTheWebAsync を待っており、AccessTheWebAsync は現時点で GetStringAsync を待っています。興味深いことに、AccessTheWebAsync は、おそらく待機時間を節約するために、待機する前にいくつかの作業 (#4) を実行しました。外部の呼び出し元 (およびチェーン内のすべての呼び出し元) も同じようにマルチタスクを自由に実行できます。これが、この「非同期」機能の最大の利点です。同期しているように感じます..または正常ですが、そうではありません。
#2と#6は分割されているので、#4(待機中の作業)の利点があります。しかし、分割せずにそれを行うこともできます。したがって、#2は次のようになりますstring urlContents = await client.GetStringAsync("...");
。ここでは利点は見られませんが、チェーンのどこかで 1 つの関数が分割され、残りの関数は分割せずにそれを呼び出します。使用するチェーン内の関数/クラスによって異なります。関数から関数へのこの動作の変化は、このトピックで最も紛らわしい部分です。
メソッドはすでに返されていることを忘れないでください (#2)。再度返すことはできません (2 回目はありません)。では、発信者はどのように知るのでしょうか? タスクがすべてです。タスクが返されました。タスクのステータスが待機されました(メソッドではなく、値ではありません)。値はタスクに設定されます。タスクのステータスは完了に設定されます。Caller は Task(#6) を監視するだけです。したがって、6# は、どこで/誰が結果を取得するかに対する答えです。詳細については、後でここを参照してください。
酒を学ぶための質問の内省: 1 分
質問を少し調整しましょう。
いつ、どのように使用するのですか? async
await
Tasks
学習Task
は自動的に他の 2 つをカバーするため (そして質問に答えます)。
全体のアイデアはとてもシンプルです。メソッドは任意のデータ型 (double、int、object など) を返すことができますが、ここではそれを拒否し、強制的に ' Task
' オブジェクトを返します! しかし、まだ戻りデータ (void を除く) が必要ですよね? Task
これは、' ' オブジェクト内の標準プロパティ (例: ' Result
' プロパティ) で設定されます。
シンタックス シュガーをすばやく理解する: 5 分
internal static int Method(int arg0, int arg1)
{
int result = arg0 + arg1;
IO(); // Do some long running IO.
return result;
}
internal static Task<int> MethodTask(int arg0, int arg1)
{
Task<int> task = new Task<int>(() => Method(arg0, arg1));
task.Start(); // Hot task (started task) should always be returned.
return task;
}
await または async について言及しましたか? いいえ。上記のメソッドを呼び出すと、監視できるタスクが取得されます。タスクが何を返すかはすでにわかっています..整数です。
- Task の呼び出しは少しトリッキーで、キーワードが表示され始めるのはそのときです。元のメソッドを呼び出すメソッド (非非同期) があった場合は、以下のように編集する必要があります。MethodTask() を呼び出しましょう
internal static async Task<int> MethodAsync(int arg0, int arg1)
{
int result = await HelperMethods.MethodTask(arg0, arg1);
return result;
}
上記と同じコードを下の画像として追加します。

- タスクが完了するのを「待っています」。したがって、
await
(必須の構文)
- await を使用するため、使用する必要があります
async
(必須の構文)
- 接頭辞としてMethodAsync を
Async
使用 (コーディング標準)
await
はわかりやすいですが、残りの 2 つ ( async
、Async
) はそうではないかもしれません:)。まあ、それはコンパイラにとってもっと理にかなっているはずです.Further read for later here
したがって、2 つの部分があります。
「タスク」を作成します(タスクは1つだけで、追加のメソッドになります)
タスクを呼び出すためのシンタックス シュガーを作成しますawait+async
(非非同期メソッドを変換する場合は、既存のコードを変更する必要があります)。
AccessTheWebAsync() への外部呼び出し元があったことを思い出してください。その呼び出し元も例外ではありません... つまり、同じものawait+async
も必要です。そしてチェーンは続きます (したがって、これは多くのクラスに影響を与える可能性のある重大な変更です)。また、元のメソッドがまだ呼び出されるため、破壊的でない変更と見なすこともできます。重大な変更を加えたい場合は、アクセス権を変更 (またはタスク内で削除して移動) すると、クラスは強制的にタスク メソッドを使用するようになります。とにかく、非同期呼び出しでは、常にTask
一方の端に があり、1 つしかありません。
大丈夫ですが、ある開発者はTask
行方不明を見て驚いていました...
開発者の混乱を共有する: 5 分
開発者が実装しないというミスを犯しましたTask
が、それでも機能します! 質問と、ここで提供されている受け入れられた回答だけを理解するようにしてください。あなたが読んで完全に理解したことを願っています。要約すると、「タスク」は表示/実装されていない可能性がありますが、親/関連クラスのどこかに実装されています。同様に、私たちの例では、すでに構築された を呼び出す方が、 ( ) ourselfMethodAsync()
を使用してそのメソッドを実装するよりもはるかに簡単です。ほとんどの開発者は、コードを非同期コードに変換する際に頭を悩ませるのが難しいと感じています。Task
MethodTask()
Tasks
ヒント: 既存の Async 実装 (MethodAsync
や などToListAsync
) を探して、問題を外部委託してください。したがって、Async と await を処理するだけで済みます (これは簡単で、通常のコードとよく似ています)。
問題: 通常のコードの実際の実装を非同期操作にすばやく変更する: 2 分
以下のデータ層のコード行が壊れ始めました (多くの場所)。コードの一部を .Net Framework 4.2.* から .Net コアに更新したためです。アプリケーション全体でこれを 1 時間で修正する必要がありました。
var myContract = query.Where(c => c.ContractID == _contractID).First();
簡単!
- QueryableExtensions があるため、EntityFramework nuget パッケージをインストールしました。つまり、Async の実装 (タスク) を行うため、シンプルなコードで生き残ることができ
Async
ますawait
。
- 名前空間 = Microsoft.EntityFrameworkCore
呼び出しコード行はこのように変更されました
var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
- メソッド シグネチャが から変更されました
Contract GetContract(int contractnumber)
に
async Task<Contract> GetContractAsync(int contractnumber)
- 呼び出しメソッドも影響を受けました:
GetContract(123456);
として呼び出されましたGetContractAsync(123456).Result;
待って!それは何Result
ですか?よく釣れます!必要な値ではない ( )GetContractAsync
のみを返します。操作の結果が利用可能になると、それは保存され、その後のプロパティへの呼び出しですぐに返されます。同様の「Wait()」でタイムアウトの実装を行うこともできますTask
Contract
Result
TimeSpan ts = TimeSpan.FromMilliseconds(150);
if (! t.Wait(ts)) Console.WriteLine("タイムアウト間隔が経過しました。");
- 30分でどこでも変えました!
しかし、アーキテクトは、これだけのために EntityFramework ライブラリを使用しないように私たちに言いました! おっとっと!ドラマ!次に、カスタム Task 実装を作成しました (yuk!)。あなたがどのように知っているか。それでも簡単!..まだユク..
次はどこへ?Converting Synchronous Calls to Asynchronous in ASP.Net Core
について見ることができるすばらしい簡単なビデオがあります。おそらく、これを読んだ後に進む方向です。それとも十分に説明しましたか?;)