繁体   English   中英

await关键字阻塞主线程

[英]await keyword blocks main thread

所以我有以下代码

private async void button1_Click(object sender, EventArgs e)
{
    await DoSomethingAsync();

    MessageBox.Show("Test");
}

private async Task DoSomethingAsync()
{
    for (int i = 0; i < 1000000000; i++)
    {
        int a = 5;
    }; // simulate job

    MessageBox.Show("DoSomethingAsync is done");

    await DoSomething2Async();
}

private async Task DoSomething2Async()
{
    for (int i = 0; i < 1000000000; i++)
    {
        int a = 5;
    } // simulate job

    MessageBox.Show("DoSomething2Async is done");
}

直到两个MessageBox都显示为主线程是块(我的意思是应用程序本身被冻结)。 我的代码显然有问题,我无法弄清楚是什么。 我以前从未使用async / await。 这是我的第一次尝试。

编辑:

实际上我想要做的是异步启动DoSomethingAsync执行,以便在单击按钮时MessageBox.Show("Test"); 即使DoSomethingAsync不完整也会执行。

我想你误解了异步意味着什么。 这并不意味着该方法在另一个线程中运行!!

异步方法同步运行直到第一个await ,然后将一个Task返回给调用者(除非它是async void ,然后它什么都不返回)。 当正在等待的任务完成时,执行将在await之后继续执行,通常在同一个线程上(如果它具有SynchronizationContext )。

在你的情况下, Thread.Sleep在第一个await之前,所以它在控制返回给调用者之前同步执行。 但即使它在await ,它仍然会阻止UI线程,除非你专门配置awaiter不捕获同步上下文(使用ConfigureAwait(false) )。

Thread.Sleep是一种阻塞方法。 如果你想要一个异步等价物,请按照Sriram Sakthivel的回答中的建议使用await Task.Delay(3000) 它将立即返回,并在3秒后恢复,而不会阻止UI线程。

异步与多线程有关,这是一种常见的误解。 它可以,但在许多情况下它不是。 由于该方法是async ,因此不会隐式生成新线程; 对于要生成的新线程,必须在某个时刻明确地完成。 如果您特别希望该方法在不同的线程上运行,请使用Task.Run

您应该注意,标记为async方法在缺少await时将不再表现为异步。 你有关于这个的编译器警告。

警告1此异步方法缺少“等待”操作符并将同步运行。 考虑使用'await'运算符等待非阻塞API调用,或'await Task.Run(...)'在后台线程上执行CPU绑定工作。

你应该注意那些警告。

异步进行。 当我说异步时,它实际上是异步而不是另一个线程中的同步作业。 使用真正异步的Task.Delay 使用Task.Run执行一些耗时的CPU作业。

private async void button1_Click(object sender, EventArgs e)
{
   await DoSomethingAsync();
}

private async Task DoSomethingAsync()
{
    await Task.Delay(3000); // simulate job

    MessageBox.Show("DoSomethingAsync is done");

    await DoSomething2Async();
}

private async Task DoSomething2Async()
{
    await Task.Delay(3000); // simulate job

    MessageBox.Show("DoSomething2Async is done");
}

你没有异步做任何事情。 尝试:

await Task.Run(() => Thread.Sleep(3000))

当你等待一个方法时,你实际上正在做的是提供一个回调,其后面的代码就像它完成后执行的那样(在以前的async版本中,你实际上必须自己设置它)。 如果您没有await任何东西,那么该方法实际上不是异步方法。

有关详细信息,您可能会比在此处查看更糟糕:

http://msmvps.com/blogs/jon_skeet/archive/2011/05/08/eduasync-part-1-introduction.aspx

编辑后; 试试这个:

public void MyMessageBox()
{
  var thread = new Thread(() =>
  {
      MessageBox.Show(...);
  });
  thread.Start();
}

虽然,你确定它真的是你想要的消息框吗? 我原以为状态栏/进度条更新会更合适。

DoSomethingAsync Thread.Sleepawait之前调用,在DoSomething2Async没有完成异步任务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM