上記の2つのペアの違いを探していましたが、それについて明確に説明している記事や、いつ使用するかについては見つかりませんでした。
SaveChanges()
とSaveChangesAsync()
の違いは何ですか?
そしてFind()
とFindAsync()
の間?
サーバー側では、Async
メソッドを使用する場合、await
も追加する必要があります。したがって、サーバー側では非同期だとは思いません。
クライアント側のブラウザーでUIのブロックを防ぐのに役立つだけですか?またはそれらの間に長所と短所はありますか?
リモートサーバーでアクションを実行する必要があるときはいつでも、プログラムは要求を生成し、送信してから応答を待ちます。例としてSaveChanges()
とSaveChangesAsync()
を使用しますが、Find()
とFindAsync()
にも同じことが当てはまります。
データベースに追加する必要がある100以上のアイテムのリストmyList
があるとします。それを挿入するには、関数は次のようになります。
using(var context = new MyEDM())
{
context.MyTable.AddRange(myList);
context.SaveChanges();
}
最初にMyEDM
のインスタンスを作成し、リストmyList
をテーブルMyTable
に追加してから、SaveChanges()
を呼び出してデータベースへの変更を永続化します。希望どおりに機能し、レコードはコミットされますが、プログラムはコミットが完了するまで他に何もできません。これは、コミットする内容によっては時間がかかる場合があります。レコードへの変更をコミットする場合、エンティティはそれらを一度にコミットする必要があります(保存に更新に2分かかったことがあります)!
この問題を解決するには、次の2つのいずれかを実行できます。 1つ目は、挿入を処理する新しいスレッドを起動できることです。これにより、実行を継続するために呼び出しスレッドが解放されますが、そこに座って待機する新しいスレッドを作成しました。そのオーバーヘッドは不要であり、これがasync await
パターンによって解決されます。
I/O操作の場合、await
はすぐに親友になります。上記のコードセクションを使用して、次のように変更できます。
using(var context = new MyEDM())
{
Console.WriteLine("Save Starting");
context.MyTable.AddRange(myList);
await context.SaveChangesAsync();
Console.WriteLine("Save Complete");
}
非常に小さな変更ですが、コードの効率とパフォーマンスに大きな影響があります。それでどうなりますか?コードの始まりは同じです。MyEDM
のインスタンスを作成し、myList
をMyTable
に追加します。しかし、await context.SaveChangesAsync()
を呼び出すと、コードの実行 呼び出し元の関数に戻ります! そのため、これらすべてのレコードがコミットされるのを待っている間、コードの実行を継続できます。上記のコードを含む関数の署名がpublic async Task SaveRecords(List<MyTable> saveList)
であったとすると、呼び出し元の関数は次のようになります。
public async Task MyCallingFunction()
{
Console.WriteLine("Function Starting");
Task saveTask = SaveRecords(GenerateNewRecords());
for(int i = 0; i < 1000; i++){
Console.WriteLine("Continuing to execute!");
}
await saveTask;
Console.Log("Function Complete");
}
なぜこのような関数を使用するのか、私にはわかりませんが、それが出力するものはasync await
の仕組みを示しています。最初に何が起こるかを見てみましょう。
実行はMyCallingFunction
、Function Starting
を入力し、Save Starting
がコンソールに書き込まれ、次に関数SaveChangesAsync()
が呼び出されます。この時点で、実行はMyCallingFunction
に戻り、 'Continuing to Execute'を最大1000回書き込むforループに入ります。 SaveChangesAsync()
が終了すると、実行はSaveRecords
functionに戻り、Save Complete
をコンソールに書き込みます。 SaveRecords
のすべてが完了すると、SaveChangesAsync()
が終了したときにMyCallingFunction
で実行が続行されます。混乱した?出力例を次に示します。
関数の開始 保存の開始 実行を継続! 実行を継続! 実行を継続! 実行を継続! 実行を継続! .... 実行を継続! 保存を完了! 実行を継続! 継続 実行を継続! .... 実行を継続! 機能完了!
または多分:
関数の開始 保存の開始 実行の継続! 実行の継続! 保存の完了! 実行の継続! 実行を継続! 実行を継続! .... 実行を継続! 機能完了!
それがasync await
の美しさです。何かが終了するのを待っている間、コードを実行し続けることができます。実際には、呼び出し関数として次のような関数があります。
public async Task MyCallingFunction()
{
List<Task> myTasks = new List<Task>();
myTasks.Add(SaveRecords(GenerateNewRecords()));
myTasks.Add(SaveRecords2(GenerateNewRecords2()));
myTasks.Add(SaveRecords3(GenerateNewRecords3()));
myTasks.Add(SaveRecords4(GenerateNewRecords4()));
await Task.WhenAll(myTasks.ToArray());
}
ここには、4つの異なるレコード保存機能があります 同時に。 MyCallingFunction
は、個々のSaveRecords
関数が連続して呼び出された場合よりも、async await
を使用するとはるかに高速に完了します。
まだ触れていないことの1つは、await
キーワードです。これは、待機中のTask
が完了するまで、現在の関数の実行を停止します。したがって、元のMyCallingFunction
の場合、SaveRecords
関数が終了するまでFunction Complete
行はコンソールに書き込まれません。
要するに、async await
を使用するオプションがある場合は、アプリケーションのパフォーマンスを大幅に向上させる必要があります。
この文は正しくありません:
サーバー側で、Asyncメソッドを使用する場合、awaitを追加する必要もあります。
「待機」を追加する必要はありません。 "await"は、C#の便利なキーワードであり、呼び出し後にコードの行をさらに記述できます。これらの他の行は、保存操作が完了した後にのみ実行されます。しかし、指摘したように、SaveChangesAsyncの代わりにSaveChangesを呼び出すだけで、それを達成できます。
しかし基本的に、非同期呼び出しはそれ以上のものです。ここでの考え方は、保存操作の進行中に(サーバー上で)他の作業ができる場合、SaveChangesAsyncを使用する必要があるということです。 「待機」を使用しないでください。 SaveChangesAsyncを呼び出してから、他の処理を並行して続けます。これには、Webアプリで、保存が完了する前でもクライアントに応答を返す可能性があります。ただし、もちろん、保存の最終結果を確認して、失敗した場合にユーザーに通知するか、何らかの方法でログに記録することができます。