使用异步/等待时发生死锁 [英] Deadlock while using async/await

查看:99
本文介绍了使用异步/等待时发生死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图理解awaitasync.

效果很好.但是现在我陷入了僵局.

It works very well. But now I have a deadlock.

我用false调用了ConfigureAwait,就像在

I've called ConfigureAwait with false, like in this article, but my code is still blocking.

这是我的代码的一小段:

Here's a little snippet of my 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;
}

推荐答案

阻止的不是任务本身,而是对Result的调用. Task表示异步操作,但是调用其Result属性或调用Wait()将阻塞当前线程,直到方法返回.而且在很多情况下,它将导致死锁,因为任务无法通过调用线程阻塞来完成!

What's blocking is not the task itself, it's the call to Result. A Task represents an asynchronous operation, but calling its Result property, or calling Wait() will block the current thread until the method returns. And in a lot of cases, it will cause a deadlock because the task is not able to complete with it's calling thread blocked!

为防止这种情况,请使用asyncawait

To prevent that, chain the tasks asynchronously, using async and 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);.

Also, Task.Delay(10).Wait(); completely defeats the prupose of using tasks in the first place: that will block the current thread. If that's really what you want to do (and it's pretty unlikely), call Thread.Sleep(10);instead, it will make your intent much clearer, and you will have less hoops to jump through. Or better, use await Task.Delay(10);in an async method.

ConfigureAwait(false)到底做什么?

它消除了继续执行任务的义务,使其可以在与任务调用者相同的上下文中运行.在大多数情况下,这意味着不再保证继续可以在同一上下文中运行.因此,如果我有方法Foo(),则要稍等一下Bar():

It removes the obligation for the continuation of the task to run in the same context as the caller of the task. In most cases that means that the continuation is no longer guaranteed to run on the same context. So if I have a method thad does Foo(), waits a little then Bar() like this one:

async Task DoStufAsync()
{
    Foo();
    await Task.Delay(10);
    Bar(); // run in the same context as Foo()
}

我保证Bar将在相同的上下文中运行.如果我有ConfigureAwait(false),就不再是这种情况了

I'm guaranteed Bar will run in the same context. If I had ConfigureAwait(false), it's no longer the case

async Task DoStufAsync()
{
    Foo();
    await Task.Delay(10).ConfigureAwait(false);
    Bar(); // can run on another thread as Foo()
}

使用ConfigureAwait(false)时,您告诉程序您不介意上下文.它可以解决一些僵局的问题,但通常不是正确的解决方案.正确的解决方案很可能永远不会以阻塞的方式等待任务,并且一直处于异步状态.

When you're using ConfigureAwait(false), you tell your program you dont mind about the context. It can solve some deadlocking problems, but isn't usually the right solution. The right solution is most likely never to wait for tasks in a blocking way, and being asynchronous all the way.

这篇关于使用异步/等待时发生死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆