什么时候最好使用 Task.Result 而不是等待 Task [英] When is the best place to use Task.Result instead of awaiting Task

查看:26
本文介绍了什么时候最好使用 Task.Result 而不是等待 Task的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Whilst I've been using async code in .NET for a while, I've only recently started to research it and understand what's going on. I've just been going through my code and trying to alter it so if a task can be done in parallel to some work, then it is. So for example:

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 但是我不明白为什么我要等待我的用户对象被获取,如果我可以在同一时间?

My understand is that the user object is now being fetched from the database WHILST some unrelated work is going on. 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 independant logic at the same time?

推荐答案

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

Let's make sure to not bury the lede here:

例如:[一些正确的代码]变成了[一些错误的代码]

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

永远不要这样做.

您可以重组控制流以提高性能的直觉非常好且正确.使用 Result 这样做是错误的错误错误.

Your instinct that you can restructure your control flow to improve performance is excellent and correct. Using Result to do so is WRONG WRONG WRONG.

重写代码的正确方法是

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 不会进行异步调用.等待只是意味着如果此任务的结果尚不可用,请执行其他操作并在可用后返回此处".该调用已经异步:它返回一个任务.

Remember, await does not make a call asynchronous. Await simply means "if the result of this task is not yet available, go do something else and come back here after it is available". The call is already asynchronous: it returns a task.

人们似乎认为 await 具有共同调用的语义;它不是.相反,await 是对任务 comonad 的提取操作;它是任务的操作符,而不是调用表达式.您通常会在方法调用中看到它,因为这是将异步操作抽象为方法的常见模式.返回的任务是等待的东西,而不是调用.

People seem to think that await has the semantics of a co-call; it does not. Rather, await is the extract operation on the task comonad; it is an operator on tasks, not call expressions. You normally see it on method calls simply because it is a common pattern to abstract away an async operation as a method. The returned task is the thing that is awaited, not the call.

但是,我所看到的内容暗示应该很少使用 result 并且首选 await 但我不明白如果我可以执行其他一些独立的操作,我为什么要等待我的用户对象被获取同时逻辑?

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 可以让你同时执行其他独立的逻辑???结果使您无法做到这一点.结果是同步等待.您的线程在同步等待任务完成时不能做任何其他工作.使用异步等待来提高效率.请记住,await 仅表示在此任务完成之前,此工作流无法进一步进行,因此如果未完成,请找到更多工作要做,稍后再回来".正如您所注意到的,过早的 await 可能会导致工作流效率低下,因为有时即使任务未完成,工作流也可以取得进展.

Why do you believe that using Result will allow you to perform other independent logic at the same time??? Result prevents you from doing exactly that. Result is a synchronous wait. Your thread cannot be doing any other work while it is synchronously waiting for the task to complete. Use an asynchronous wait to improve efficiency. Remember, await simply means "this workflow cannot progress further until this task is completed, so if it is not complete, find more work to do and come back later". A too-early await can, as you note, make for an inefficient workflow because sometimes the workflow can progress even if the task is not complete.

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

By all means, move around where the awaits happen to improve efficiency of your workflow, but never never never change them into Result. You have some deep misunderstanding of how asynchronous workflows work if you believe that using Result will ever improve efficiency of parallelism in the workflow. Examine your beliefs and see if you can figure out which one is giving you this incorrect intuition.

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

The reason why you must never use Result like this is not just because it is inefficient to synchronously wait when you have an asynchronous workflow underway. It will eventually hang your process. Consider the following workflow:

  • task1 表示将被安排在将来在此线程上执行并产生结果的作业.
  • 异步函数 Foo 等待 task1.
  • task1 还没有完成,所以 Foo 返回,允许这个线程运行更多的工作.Foo 返回一个代表其工作流的任务,并将完成该任务作为 task1 的完成.
  • 该线程现在可以自由地在未来工作,包括 task1.
  • task1完成,触发执行Foo工作流的完成,最终完成代表Foo工作流的任务.
  • task1 represents a job that will be scheduled to execute on this thread in the future and produce a result.
  • asynchronous function Foo awaits task1.
  • task1 is not yet complete, so Foo returns, allowing this thread to run more work. Foo returns a task representing its workflow, and signs up completing that task as the completion of task1.
  • The thread is now free to do work in the future, including task1.
  • task1 completes, triggering the execution of the completion of the workflow of Foo, and eventually completing the task representing the workflow of Foo.

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

Now suppose Foo instead fetches Result of task1. What happens? Foo synchronously waits for task1 to complete, which is waiting for the current thread to become available, which never happens because we're in a synchronous wait. Calling Result causes a thread to deadlock with itself if the task is somehow affinitized to the current thread. You can now make deadlocks involving no locks and only one thread! Don't do this.

这篇关于什么时候最好使用 Task.Result 而不是等待 Task的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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