![](/img/trans.png)
[英]Why is an async method with await keyword still blocking the main thread?
[英]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.Sleep
在await
之前调用,在DoSomething2Async
没有完成异步任务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.