所以我有以下代码
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
的执行,这样当单击按钮时,即使DoSomethingAsync不完整,MessageBox.Show("Test");
也会执行。
答案 0 :(得分:32)
我认为你误解了异步意味着什么。 这并不意味着该方法在另一个线程中运行!!
异步方法同步运行直到第一个await
,然后向调用者返回Task
(除非它是async void
,然后它不返回任何内容)。当正在等待的任务完成时,执行将在await
之后继续执行,通常在同一个线程上(如果它有SynchronizationContext
)。
在您的情况下,Thread.Sleep
在第一个等待之前,因此它会在控制权返回给调用者之前同步执行。但即使它在await
之后,它仍会阻止UI线程,除非您专门配置awaiter不捕获同步上下文(使用ConfigureAwait(false)
)。
Thread.Sleep
是一种阻止方法。如果你想要一个异步等价物,请按照Sriram Sakthivel的回答中的建议使用await Task.Delay(3000)
。它将立即返回,并在3秒后恢复,而不会阻止UI线程。
异步与多线程有关,这是一种常见的误解。它可以,但在许多情况下它不是。不会因为方法为async
而隐式生成新线程;对于要生成的新线程,必须在某个时刻明确地完成。如果您特别希望该方法在其他线程上运行,请使用Task.Run
。
答案 1 :(得分:10)
您应该注意,标有async
的方法在缺少await
时将不再表现为异步。你有关于此的编译器警告。
警告1此异步方法缺少'await'运算符并将运行 同步。考虑使用'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");
}
答案 2 :(得分:5)
你没有异步做任何事情。尝试:
await Task.Run(() => Thread.Sleep(3000))
当你等待一个方法时,你实际上正在做的是提供一个回调,其后面的代码就像它完成后执行的那样(在以前的异步版本中,你实际上必须自己设置它)。如果你没有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();
}
虽然,你确定它真的是你想要的消息框吗?我原以为状态栏/进度条更新会更合适。
答案 3 :(得分:0)
在DoSomethingAsync
之前调用Thread.Sleep
await
,DoSomething2Async
之前调用异步任务。