使用async await仍会冻结GUI

eug*_*ekr 9 c# user-interface asynchronous async-await

我想在单独的线程中处理长时间运行的操作,并使用async/await模式将控制返回到GUI线程,如下所示:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    await Test();
    txtResult.Text = "Done!";
}

private Task Test()
{
    Thread.Sleep(3000);
    return Task.FromResult(0);
}
Run Code Online (Sandbox Code Playgroud)

问题是,它无论如何都会冻结GUI 3秒钟(在3秒后显示Done!之前它会变得无法响应).我究竟做错了什么?

编辑:我试图取代以下逻辑:

private void Button_Click(object sender, RoutedEventArgs e)
{
    var thread = new Thread(() => Test(Callback));
    thread.Start();
}

private void Callback()
{
    Dispatcher.Invoke(() =>
        txtResult.Text = "Done!");
}

private void Test(Action callback)
{
    Thread.Sleep(3000); //long running operation, not necessarily pause
    callback();
}
Run Code Online (Sandbox Code Playgroud)

在实际项目中,我有不同的长时间运行逻辑而不仅仅是Sleep,它仍然会冻结GUI,因此用Task.Delay替换它并不能解决任何问题.此外,我不明白为什么你应该使用另一个命令睡眠?async/await设计需要什么?

Nic*_*ick 12

您可以在另一个线程上使用Task.RunTask.Factory.StartNew执行Test()或执行一些长时间运行和/或阻塞操作:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    await Task.Run(() => Test());
    txtResult.Text = "Done!";
}
Run Code Online (Sandbox Code Playgroud)

  • Test()返回一个同步任务,只是等待它不会在一个单独的线程上启动任务.[文档](https://msdn.microsoft.com/en-us/library/hh191443.aspx?f=255&MSPPError=-2147217396)解释了这个比我更好:"async和await关键字没有导致创建额外的线程." 和"您可以使用Task.Run将CPU绑定的工作移动到后台线程". (3认同)
  • 对不起,为什么它应该等待Task.Run(()=> Test()); 而不仅仅是等待Test()? (2认同)