async方法阻塞了它正在执行的UI线程

本文关键字:执行 UI 线程 方法 async | 更新日期: 2023-09-27 18:17:48

在Winform中考虑以下代码。当我点击按钮时,我期望异步方法不应该阻塞它正在执行的UI线程。

然而,我发现按钮在异步方法调用期间被冻结…如果为真,async方法的意义是什么?我很困惑。

namespace WindowsFrmAsyn
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        async private void button1_Click(object sender, EventArgs e)
        {
            int contentlength = await AccessTheWebAsync();
            tbResult.Text =
                        string.Format("Length of the downloaded string: {0}.", contentlength);
            Debug.WriteLine(tbResult.Text);
        }    
        async Task<int> AccessTheWebAsync()
        {
            Debug.WriteLine("Call AccessTheWebAsync");
            Thread.Sleep(5000);
            Debug.WriteLine("Call AccessTheWebAsync done");
            tbResult.Text = "I am in AccessTheWebAsync";
            return 1000;
        }
    }
}

async方法阻塞了它正在执行的UI线程

编译器警告告诉你发生了什么:因为你的async方法从来没有await,它将同步运行。

Thread.Sleep为同步操作;如果您想执行异步操作,请使用Task.Delay:

async Task<int> AccessTheWebAsync()
{
  Debug.WriteLine("Call AccessTheWebAsync");
  await Task.Delay(5000);
  Debug.WriteLine("Call AccessTheWebAsync done");
  tbResult.Text = "I am in AccessTheWebAsync";
  return 1000;
}

目前你在accessthewebsync中缺少await,因为你没有等待任何东西,所以所有代码都在主线程上运行。Async/await不会让方法在不同的线程上运行,除了你等待的部分。

方法必须是这样的。

async Task<int> AccessTheWebAsync()
{
     // Console writeline
     await Task.Delay(seconds);
     // Console WriteLine.
     return value;
}

因此,async方法中的await之前和之后的所有内容都在调用该方法的同一个线程上运行。你可以选择使用ConfigureAwait,这是在库中常用的,这样等待之后的所有事情都将发生在等待完成的同一个线程上。

查看http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-await-faq.aspx获取更多关于async/await的信息

当您编写这样的代码时:

private async Task<int> DoStuffAsync()
{
    return 0;
}

这样做是同步的,因为你没有使用await表达式。

注意警告:

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

根据警告建议,您可以这样修改:

private async Task<int> DoStuffAsync()
{
    return await Task.Run<int>(() =>
    {
        return 0;
    });
}