我正在尝试了解await和async。 它工作得很好。但现在我陷入僵局。我将ConfigureAwait称为false,如本文所述:http://blog.ciber.no/2014/05/19/using-task-configureawaitfalse-to-prevent-deadlocks-in-async-code/ 但我的代码仍在阻止。 这是我的代码中的一小部分:
private void button1_Click(object sender, EventArgs e)
{
var result = HeavyWorkAsync().Result;
richTextBox1.AppendText(result);
}
private string HeavyWork()
{
for (var index = 0; index < 1000; index++)
{
Task.Delay(10).Wait();
}
return "finished";
}
private async Task<string> HeavyWorkAsync()
{
var task = await Task.Factory.StartNew<string>(HeavyWork).ConfigureAwait(false);
return task;
}
答案 0 :(得分:2)
什么阻止不是任务本身,而是对Result
的呼叫。 Task
表示异步操作,但调用其Result
属性或调用Wait()
将阻止当前线程,直到该方法返回。在很多情况下,它会导致死锁,因为任务无法完成它的调用线程被阻止!
为防止这种情况,请使用async
和await
private async void button1_Click(object sender, EventArgs e)
{
var result = await HeavyWorkAsync(); // <=== await
richTextBox1.AppendText(result);
}
此外,Task.Delay(10).Wait();
完全取消了首先使用任务的目的:这将阻止当前线程。如果真的你想做什么(并且它不太可能),请拨打Thread.Sleep(10);
,这会让你的意图更加清晰,你会有跳得越少越好。或者更好的是,在异步方法中使用await Task.Delay(10);
。
ConfigureAwait
ConfigureAwait(false)
究竟做了什么?
它消除了继续任务在与任务调用者相同的上下文中运行的义务。在大多数情况下,这意味着不再保证延续在相同的上下文中运行。所以,如果我有一个方法thad Foo()
,那么稍等一点Bar()
就像这样:
async Task DoStufAsync()
{
Foo();
await Task.Delay(10);
Bar(); // run in the same context as Foo()
}
我保证Bar会在同一个环境中运行。如果我有ConfigureAwait(false)
,则不再是这种情况
async Task DoStufAsync()
{
Foo();
await Task.Delay(10).ConfigureAwait(false);
Bar(); // can run on another thread as Foo()
}
当您使用ConfigureAwait(false)
时,您告诉您的程序您不介意上下文。它可以解决一些死锁问题,但通常不是正确的解决方案。正确的解决方案很可能永远不会以阻塞的方式等待任务,并且一直是异步的。
答案 1 :(得分:1)
要扩展Falanwe的答案,您应该查看Stephen Cleary's blog post。基于代码,我假设您使用的是Windows窗体应用程序,因此对Task.Result的调用将在UI上下文中执行任务,从而阻止UI线程。