我们需要有“双重等待”以避免GUI冻结吗?

3

在阅读了使用 Async 和 Await 进行异步编程 (C# 和 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;
    }

但是实际情况并非如此。它仍然卡住了。 我意识到我需要在 DoBusyJob 中添加额外的await

    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
async 关键字并不会神奇地使你的 for 循环代码在后台线程上运行。你想要做的是 await Task.Run( () => DoExpensiveCpuCalculations()); - cordialgerm
3个回答

6
请参阅这个问题的优秀答案,涉及async方法。
如果您未使用已经异步的方法并带有await,则添加async是不足以使您的方法异步执行的。在这种情况下,您需要返回一个Task实例来表示您的工作执行,例如通过调用Task.Factory.StartNew

2

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

问:在方法上使用“async”关键字是否会强制该方法的所有调用都异步执行?

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

问:使用“async”关键字会将方法的调用排队到线程池吗?会创建新线程吗?会发射火箭前往火星吗?

答:不会。不会。也不会...

您可能会发现我的async / await介绍有所帮助。


0

我希望我能理解你在添加awaitThread.Sleep(10000);时的// OK!
在返回voidSleep()方法上不可能使用await
只有指定其签名为TaskTask<TResult>作为返回类型的方法才能使用await

异步方法会同步执行,直到出现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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接