21

だから私は次のコードを持っています

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 が不完全であっても実行されるように、非同期的に実行を開始することです。

4

4 に答える 4

40

非同期の意味を誤解していると思います。メソッドが別のスレッドで実行されるという意味ではありません!!

非同期メソッドは、最初の まで同期的に実行され、呼び出し元awaitに a を返します(それが でない限り、何も返しません)。待機中のタスクが完了すると、 の後に実行が再開され、通常は同じスレッドで実行されます ( がある場合)。Taskasync voidawaitSynchronizationContext

あなたの場合、Thread.Sleep最初の待機の前にあるため、制御が呼び出し元に返される前に同期的に実行されます。ただし、 の後であったとしても、await( を使用して) 同期コンテキストをキャプチャしないように awaiter を具体的に構成しない限り、UI スレッドは引き続きブロックされますConfigureAwait(false)

Thread.Sleepブロッキング方法です。同等の非同期が必要な場合await Task.Delay(3000)は、Sriram Sakthivel の回答で提案されているように を使用します。UI スレッドをブロックすることなく、すぐに戻り、3 秒後に再開します。

非同期がマルチスレッドに関連しているというのはよくある誤解です。そうかもしれませんが、多くの場合そうではありません。asyncメソッドが;であるため、新しいスレッドが暗黙的に生成されることはありません。新しいスレッドを生成するには、ある時点で明示的に実行する必要があります。メソッドを別のスレッドで実行したい場合は、Task.Run.

于 2013-11-06T13:52:09.207 に答える
8

あなたは非同期的に何もしていません。試す:

await Task.Run(() => Thread.Sleep(3000))

メソッドを待機するとき、効果的に行っているのはコールバックを提供することであり、コールバックに続くコードは、終了後に実行されるものとして実行されます (以前の async の化身では、実際にこれを自分で設定する必要がありました)。何もしない場合await、メソッドは実際には非同期メソッドではありません。

詳細については、ここを見るよりも悪いことをすることができます:

http://msmvps.com/blogs/jon_skeet/archive/2011/05/08/eduasync-part-1-introduction.aspx

あなたの編集に続いて; これを試して:

public void MyMessageBox()
{
  var thread = new Thread(() =>
  {
      MessageBox.Show(...);
  });
  thread.Start();
}

しかし、それは本当にあなたが望むメッセージボックスですか? ステータスバー/プログレスバーの更新の方が適していると思いました。

于 2013-11-06T13:46:53.707 に答える
0

In the DoSomethingAsync Thread.Sleep is called before await and in DoSomething2Async no async task is done.

于 2013-11-06T13:49:57.430 に答える