gpt4 book ai didi

c# - 什么时候使用 Task.Result 而不是等待 Task 的最佳位置

转载 作者:太空狗 更新时间:2023-10-29 19:49:06 26 4
gpt4 key购买 nike

虽然我在 .NET 中使用异步代码已有一段时间,但我最近才开始研究它并了解发生了什么。我一直在检查我的代码并试图改变它,所以如果一个任务可以与一些工作并行完成,那么它就是。例如:

var user = await _userRepo.GetByUsername(User.Identity.Name);

//Some minor work that doesn't rely on the user object

user = await _userRepo.UpdateLastAccessed(user, DateTime.Now);

return user;

现在变成:

var userTask = _userRepo.GetByUsername(User.Identity.Name);

//Some work that doesn't rely on the user object

user = await _userRepo.UpdateLastAccessed(userTask.Result, DateTime.Now);

return user;

我的理解是,用户对象现在正在从数据库中获取,同时一些不相关的工作正在进行。但是,我看到的帖子暗示 result 应该很少使用并且 await 是首选,但我不明白为什么我要等待我的用户对象被获取,如果我可以在同一时间?

最佳答案

让我们确保不要把 lede 埋在这里:

So for example: [some correct code] becomes [some incorrect code]

永远永远永远不要这样做。

您认为可以重组控制流以提高性能的直觉是极好的和正确的。使用 Result 这样做是错误的,错误的。

重写代码的正确方法是

var userTask = _userRepo.GetByUsername(User.Identity.Name);    
//Some work that doesn't rely on the user object
user = await _userRepo.UpdateLastAccessed(await userTask, DateTime.Now);
return user;

请记住,await 不会进行异步调用。等待只是意味着“如果此任务的结果尚不可用,请去做其他事情并在可用后返回这里”。该调用已经是异步的:它返回一个任务

人们似乎认为 await 具有共同调用的语义;它不是。相反,await 是任务 comonad 上的 extract 操作;它是任务的运算符,而不是调用表达式。您通常会在方法调用中看到它,因为它是将异步操作抽象为方法的常见模式。 返回的任务是等待的事情,而不是调用

However, things I've seen posted imply that result should be used rarely and await is preferred but I don't understand why I'd want to wait for my user object to be fetched if I can be performing some other independent logic at the same time?

为什么您认为使用 Result 将允许您同时执行其他独立逻辑??? Result 会阻止你这样做。结果是同步等待。您的线程在同步等待任务完成时不能做任何其他工作。使用异步等待 来提高效率。请记住,await 仅表示“此工作流程无法进一步推进,直到此任务完成,因此如果未完成,请找到更多工作要做,稍后再回来”。正如您所注意到的,过早的 await 可能会导致工作流效率低下,因为有时即使任务未完成,工作流也可以继续进行。

一定要在等待发生的地方移动以提高工作流的效率,但永远不要永远不要将它们更改为Result。如果您认为使用 Result 将永远提高工作流中的并行效率,那么您对异步工作流的工作方式有一些深刻的误解。检查您的信念,看看您是否能找出是哪个信念给了您这种不正确的直觉。

你绝不能像这样使用 Result 的原因不仅仅是因为当你有一个正在进行的异步工作流时同步等待是低效的。 它最终会挂起你的进程。考虑以下工作流程:

  • task1 表示将被安排在将来此线程上执行并产生结果的作业。
  • 异步函数 Foo 等待 task1。
  • task1 尚未完成,因此 Foo 返回,允许该线程运行更多工作。 Foo 返回一个代表其工作流程的任务,并注册完成该任务作为 task1 的完成。
  • 线程现在可以自由地处理 future 的工作,包括 task1
  • task1完成,触发Foo工作流完成的执行,最终完成代表Foo工作流的任务。

现在假设 Foo 改为获取 task1Result。怎么了? Foo 同步等待 task1 完成,它正在等待当前线程可用,这永远不会发生,因为我们处于同步等待如果任务以某种方式关联到当前线程,则调用 Result 会导致线程与自身发生死锁。您现在可以制造不涉及锁且只有一个线程的死锁!不要这样做。

关于c# - 什么时候使用 Task.Result 而不是等待 Task 的最佳位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47284290/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com