次のようなコードがあります
private async void button1_Click(object sender, EventArgs e)
{
await DoSomethingAsync();
MessageBox.Show("Test");
}
private async Task DoSomethingAsync()
{
for (int i = 0; i < 1000000000; i++)
{
int a = 5;
}; // simulate job
MessageBox.Show("DoSomethingAsync is done");
await DoSomething2Async();
}
private async Task DoSomething2Async()
{
for (int i = 0; i < 1000000000; i++)
{
int a = 5;
} // simulate job
MessageBox.Show("DoSomething2Async is done");
}
両方の MessageBoxes が表示されるまで、メイン スレッドはブロックされます (つまり、アプリケーション自体がフリーズします)。明らかにコードに何か問題がありますが、何が問題なのかわかりません。これまで async/await を使用したことはありません。これが初めての試みです。
編集:
実際、私がやりたいのは、DoSomethingAsync
ボタンがクリックされたときにMessageBox.Show("Test");
DoSomethingAsync が不完全であっても実行されるように、非同期で実行を開始することです。
ベストアンサー1
あなたは async の意味を誤解していると思います。メソッドが別のスレッドで実行されるという意味ではありません!!
非同期メソッドは、最初の まで同期的に実行されawait
、その後、Task
呼び出し元に を返します ( の場合は何も返しません)。待機中のタスクが完了すると、通常は同じスレッド ( がある場合)でasync void
の後に実行が再開されます。await
SynchronizationContext
あなたの場合、 はThread.Sleep
最初の await の前にあるため、制御が呼び出し元に返される前に同期的に実行されます。ただし、 の後であったとしても、待機側が同期コンテキストをキャプチャしないように明示的に構成しない限り ( を使用) await
、UI スレッドはブロックされます。ConfigureAwait(false)
Thread.Sleep
はブロッキング メソッドです。非同期の同等のものが必要な場合は、await Task.Delay(3000)
Sriram Sakthivel の回答で提案されているように を使用してください。UI スレッドをブロックすることなく、すぐに戻り、3 秒後に再開します。
async がマルチスレッドに関連しているというのはよくある誤解です。そうである場合もありますが、多くの場合はそうではありません。メソッドが であるからといって、新しいスレッドが暗黙的に生成されるわけasync
ではありません。新しいスレッドを生成するには、ある時点で明示的に行う必要があります。メソッドを別のスレッドで実行することを明確にしたい場合は、 を使用しますTask.Run
。