我们需要“双”等待,以便GUI不会冻结?

时间:2012-10-18 03:50:46

标签: c# user-interface responsive-design task-parallel-library async-await

我希望在阅读Asynchronous Programming with Async and Await (C# and Visual Basic)

后,我的GUI不会挂起
    public async Task<string> DoBusyJob()
    {
        // Busy Job
        Thread.Sleep(10000);
        i++;
        return "Finished " + i;
    }

    int i = 0;

    private async void button1_Click(object sender, EventArgs e)
    {
        // Hang!
        string result = await DoBusyJob();

        this.label1.Text = result;
    }

但事实并非如此。它仍然挂起。我意识到我需要在await中添加额外的DoBusyJob

    public async Task<string> DoBusyJob()
    {
        // Busy Job
        await Thread.Sleep(10000);
        i++;
        return "Finished " + i;
    }

    int i = 0;

    private async void button1_Click(object sender, EventArgs e)
    {
        // OK!
        string result = await DoBusyJob();

        this.label1.Text = result;
    }

我可以知道为什么会这样吗?我真的需要加倍 await吗?如果出现以下情况怎么办?

    public async Task<string> DoBusyJob()
    {
        // How to prevent Hang?
        for (int j = 0; j < 10000000; j++) {
            double m = Math.Sqrt(1) + Math.Sqrt(2) + Math.Sqrt(3);
        }
        i++;
        return "Finished " + i;
    }

    int i = 0;

    private async void button1_Click(object sender, EventArgs e)
    {
        // Hang!
        string result = await DoBusyJob();

        this.label1.Text = result;
    }

3 个答案:

答案 0 :(得分:6)

有关async方法的信息,请参阅the excellent answers to this question

如果您没有使用已经异步的async方法,则添加await不足以使您的方法的执行异步。在这种情况下,您需要返回一个代表您的工作执行的Task实例,例如。致电Task.Factory.StartNew

答案 1 :(得分:2)

async / await FAQ中有一个很好的答案:

  

Q值。在方法上使用“async”关键字是否强制该方法的所有调用都是异步的?

     

一个。不。当您调用标记为“async”的方法时,它会在当前线程上开始同步运行...

     

Q值。 “async”关键字是否导致调用方法以排队到ThreadPool?要创建新线程?发射火箭飞往火星?

     

一个。不,不,不......

您可能会发现我的async / await intro有帮助。

答案 2 :(得分:0)

我希望在将// OK!添加到await后,我能理解您的Thread.Sleep(10000); 无法等待方法Sleep()返回void
只能在方法上指定其签名TaskTask<TResult>作为返回类型

异步方法在没有(或直到)await的情况下同步执行,因此阻止了UI线程
await Task.Run()应立即返回(上一个)UI同步上下文,即继续下一个i ++;行执行

public async Task<string> DoBusyJob()
{
  // Busy Job

  await Task.Run(() =>
    {
        for (int j = 0; j < 10000000; j++)
        {
            double m = Math.Sqrt(1) + Math.Sqrt(2) + Math.Sqrt(3);
        }
    }
                );
  i++;
  return "Finished " + i;
}