使用async/await时GUI会冻结

3

我正在尝试找出下面代码的问题。我原以为使用async和await让我忘记GUI问题,例如某些长时间运行的代码阻塞主线程。

在我点击按钮后,GUI响应良好,直到调用longRunningMethod,如下所示:

 private async void openButton_Click(object sender, RoutedEventArgs e)
 {
    //doing some usual stuff before calling downloadFiles
    Task<int> result = await longRunningMethod(); // async method

    //at this point GUI becomes unresponsive

    //I'm using the result here, so I can't proceed until the longRunningMethod finishes

  }

在方法完成之前,我无法继续进行,因为我需要 result。为什么这段代码会导致我的应用程序冻结?


longRunningMethod() 的内部可能通过不正确使用 async/await 阻塞了 UI 线程。 - thumbmunkeys
1
@Adwaenyth 这完全不正确。IO绑定操作不需要新线程来停止阻塞UI。 - Daniel Kelley
1
我注意到你没有返回Task<int>。longRunningMethod是否启动了一个新任务? - mrsargent
1
@DanielKelley 猜测这个方法中运行的操作不是IO绑定的。 - Adwaenyth
1
@user4205580,你能详细介绍一下longRunningMethod()里面的内容吗? - thumbmunkeys
显示剩余3条评论
1个回答

8
问题出在longRunningMethod方法内部。
这段代码可能正在执行一些CPU密集型或阻塞操作。
如果你想在后台线程上运行一些CPU密集型的代码,必须显式地这样做;async不会自动跳转线程。
int result = await Task.Run(() => longRunningMethod());

请注意,如果longRunningMethod是CPU密集型的,则其应具有同步而非异步的签名。
如果longRunningMethod不是CPU密集型的(即它当前正在阻塞),则需要将longRunningMethod内的阻塞方法调用更改为异步,并通过await进行调用。然后您可以使longRunningMethod异步化,并通过await进行调用:
int result = await longRunningMethodAsync();

我不确定是否理解 - GUI 有一个异步方法,当您按下按钮时会调用该方法。 当我调用 await longRunningMethod 时,这意味着在 longRunningMethod 完成之前,按钮方法中的任何代码都不会执行。 在此期间,执行将返回到调用 openButton_Click 方法的方法。 执行异步方法 longRunningMethod 应该创建一个单独的线程,对吗? 这就是 async 和 await 的想法,正如我所说的那样。 - user4205580
什么是CPU绑定和阻塞操作?我认为第一个是当操作使用100%的CPU功率时,第二个是当等待某些资源时。但我没有想到这可能会导致任何问题,比如GUI冻结(我认为在这种情况下多个线程也可以同时运行)。 - user4205580
@user4205580:不,执行异步方法并不会创建一个单独的线程。我有一篇关于 [async/await] 的介绍文章(http://blog.stephencleary.com/2012/02/async-and-await.html),你可能会觉得有帮助。 - Stephen Cleary
忽略细节,我会说 async/await 是多线程的模拟。两个不同代码片段的行在单个线程上交替执行。如果其中一行需要运行很长时间,那么在它完成之前将不会执行其他行。我说得对吗? - user4205580
我的意思是:http://pastebin.com/drzBVTec 这段代码在单个线程上运行(我说一个线程,因为在VS控制台中声明的退出线程数与简单的hello world情况相同)。首先打印“Async 1”行,然后await Task.Delay在异步方法中导致1毫秒的暂停,由于暂停尚未执行,控制权返回到主程序。控制台中打印的“Program…”和“Async 2…”行将交错,因此我们有两种方法同时在单个线程上运行(模拟多线程)。 - user4205580
显示剩余2条评论

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