await vs Task.Wait - Deadlock? 在异步编程中,我们经常会遇到使用`await`关键字或`Task.Wait`方法来等待异步操作完成的情况。然而,这两种方式在使用上有一些区别,并且在特定情况下可能会导致死锁问题。 `await`关键字用于等待一个异步操作完成,并返回其结果。使用`await`时,当前线程会暂时挂起,并且允许其他操作在此期间执行。一旦异步操作完成,当前线程会恢复执行。 `Task.Wait`方法也用于等待异步操作完成,但它是一个同步方法,会导致当前线程阻塞,

24 浏览
0 Comments

await vs Task.Wait - Deadlock? 在异步编程中,我们经常会遇到使用`await`关键字或`Task.Wait`方法来等待异步操作完成的情况。然而,这两种方式在使用上有一些区别,并且在特定情况下可能会导致死锁问题。 `await`关键字用于等待一个异步操作完成,并返回其结果。使用`await`时,当前线程会暂时挂起,并且允许其他操作在此期间执行。一旦异步操作完成,当前线程会恢复执行。 `Task.Wait`方法也用于等待异步操作完成,但它是一个同步方法,会导致当前线程阻塞,

我不太明白Task.Waitawait之间的区别。\n我在一个ASP.NET WebAPI服务中有类似如下函数:\n

public class TestController : ApiController
{
    public static async Task Foo()
    {
        await Task.Delay(1).ConfigureAwait(false);
        return "";
    }
    public async static Task Bar()
    {
        return await Foo();
    }
    public async static Task Ros()
    {
        return await Bar();
    }
    // GET api/test
    public IEnumerable Get()
    {
        Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
        return new string[] { "value1", "value2" }; // 这段代码永远不会执行
    }
}

\n其中Get会造成死锁。\n是什么导致了这个问题?为什么使用阻塞等待而不是await Task.Delay时不会出现问题?

0
0 Comments

在讨论(async/await vs Task.Wait - Deadlock?)这个问题之前,需要了解一些重要的事实:

- async/await在CIL级别上更复杂,因此会消耗更多的内存和CPU时间。

- 如果等待时间不可接受,任何任务都可以被取消。

- 在async/await的情况下,我们没有一个处理程序来取消或监视这样的任务。

- 使用Task比async/await更灵活。

- 任何同步功能都可以被async包装。

下面是一个示例代码:

public async Task DoAsync(long id)
{
    return await Task.Run(() => { return DoSync(id); });
}

async/await会产生许多问题。我们无法确定await语句是否会在运行时和上下文调试中被执行到。如果第一个await没有被执行到,一切都会被阻塞。有时即使await似乎被执行到了,仍然会发生阻塞,如下链接所示:

https://github.com/dotnet/runtime/issues/36063

我不明白为什么我必须为同步和异步方法而重复编写代码或使用hack。

结论:手动创建任务并对其进行控制要更好。对Task的处理程序提供了更多的控制。我们可以监视任务并对其进行管理,如下链接所示:

https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem

对于我的英语表示抱歉。

0
0 Comments

在这篇文章中,我们将讨论一个常见的问题:await和Task.Wait之间的死锁问题。首先,让我们看一下这个问题是如何产生的以及如何解决。

根据我从不同的来源中所了解到的:

await表达式不会阻塞它所在的线程。相反,它会使编译器将异步方法的其余部分作为继续处理等待的任务。控制权然后返回给异步方法的调用者。当任务完成时,它会调用其继续处理程序,并且异步方法会从离开的地方继续执行。

要等待单个任务完成,可以调用其Task.Wait方法。调用Wait方法会阻塞调用线程,直到单个任务实例完成执行。无参数的Wait()方法用于无条件地等待任务完成。任务通过调用Thread.Sleep方法来模拟工作,以便休眠两秒钟。

这篇文章也是一个很好的阅读材料。

“那这不是技术上不正确吗?有人可以请说明一下吗?”-我可以说明一下吗?你是在问一个问题吗?(我只是想明确一下你是在问还是在回答)。如果你是在问:它可能作为一个单独的问题更好;它不太可能在这里作为一个答案收集到新的回答。

我已经回答了问题,并在这里提出了一个我所怀疑的问题的单独问题。非常感谢。你能不能请取消你对答案的删除投票?

“你能不能请取消你对答案的删除投票?”-那不是我的,感谢,任何我投的票都会立即生效。然而,我认为这个答案没有回答问题的关键点,即死锁行为。

这是不正确的。在达到第一个await之前,一切都被阻塞了。尽管你是对的,这并不意味着答案是没有用的。

使用async await在技术上不会创建一个线程,并且会导致您的代码共享线程,而不是Task/Thread。异步用于不阻塞UI,线程用于非UI阻塞逻辑。

在解决await和Task.Wait之间的死锁问题时,需要注意到Task.Wait方法会阻塞当前线程,直到任务完成,而await表达式不会阻塞当前线程,而是将剩余的异步方法作为继续处理程序。因此,如果在异步方法中使用了Task.Wait方法,可能会导致死锁。为了解决这个问题,应该避免在异步方法中使用Task.Wait方法,而是使用await表达式来等待任务的完成。

希望这篇文章能帮助你理解await和Task.Wait之间的死锁问题以及如何解决它。谢谢阅读!

0
0 Comments

(await vs Task.Wait - Deadlock?)

在使用异步编程中,Waitawait 的概念相似,但实际上完全不同。

Wait 方法会同步地阻塞线程,直到任务完成。这意味着当前线程会被阻塞,等待任务完成。通常情况下,应该遵循“从头到尾都使用异步”的原则,也就是说,不要在异步代码中阻塞。在我的博客中,我详细介绍了阻塞异步代码会导致死锁的细节。

await 关键字会异步等待任务完成。这意味着当前的方法会被“暂停”(其状态会被捕获),并返回一个未完成的任务给调用者。稍后,当await表达式完成时,剩余的方法会被作为一个继续任务调度执行。

你还提到了“协作阻塞”,我猜你是指你正在等待的任务可能在等待线程上执行。确实存在这种情况,但这是一种优化。在许多情况下,这是不可能的,比如任务是为另一个调度器准备的,或者任务已经开始执行,或者任务是一个非代码任务(就像你的代码示例中的Delay任务,Wait不能在内联执行Delay任务,因为没有相关代码)。

你可能会发现我在博客中介绍的async/await入门文章有所帮助。

我认为可能存在误解,Wait方法可以正常工作,而await方法会导致死锁。

不,任务调度器不会这样做。 Wait方法会阻塞线程,而且不能用于其他目的。

我猜你只是弄混了方法名称,导致阻塞代码出现死锁,并且使用await的代码能够正常工作。要么就是死锁与这两者无关,你对问题的诊断有误。

这是设计上的问题——它在UI应用程序中效果很好,但对于ASP.NET应用程序来说可能会有些妨碍。ASP.NET Core通过移除SynchronizationContext来解决了这个问题,所以在ASP.NET Core请求中进行阻塞不再导致死锁。

这真是太奇妙了。我来这里是因为我在理解《C#并发编程实用指南》中的一部分时遇到了一些问题,然后过了一段时间我才意识到你就是作者。

0