从同步函数返回任务与空隙
I am just curious about a scenario around returning a `Task` vs `void` from a synchronous function. Given I have a function, as below, that can either return a Task or a void. I am just curious if there is any benefit in returning a `Task` rather than just a `void`?
public void SynchronousFunction(/* some input */) { /* some synchronous operation */}
// VS
public Task SynchronousFunction(/* some input */)
{
/* some synchronous operation */
return Task.CompletedTask
}
// VS Variation of Task return function
public Task SynchronousFunction(/* some input */)
{
return Task.Run(() => /* some synchronous operation */
}
我的观点是两个折。首先,感觉像返回任务需要一些不必要的拳击和拆箱,其次,如果在某些同步代码中调用函数,则不需要使用.wait()或类似的东西来调用。
I am just curious about a scenario around returning a `Task` vs `void` from a synchronous function. Given I have a function, as below, that can either return a Task or a void. I am just curious if there is any benefit in returning a `Task` rather than just a `void`?
public void SynchronousFunction(/* some input */) { /* some synchronous operation */}
// VS
public Task SynchronousFunction(/* some input */)
{
/* some synchronous operation */
return Task.CompletedTask
}
// VS Variation of Task return function
public Task SynchronousFunction(/* some input */)
{
return Task.Run(() => /* some synchronous operation */
}
My view is two fold. Firstly, it feels like returning a Task would require some unnecessary boxing and unboxing, and, secondly, if the function gets called in some synchronous code it doesn't need to be called with .Wait() or such like thing.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在第一个示例中,您的代码同步执行。呼叫线程调用该方法被阻止,等待方法执行在执行其他任何操作之前完成。
在某些情况下,这很好(例如,您需要运行的一些脚本过程以维护数据库),在其他情况下,这是一个问题(例如,在控制器代码中的ASP.NET核心应用程序中的服务器端代码)。
第二个示例基本上是相同的,但是您正在返回完成的任务。代码仍然同步完成,没有区别。呼叫者恢复了已经完成的任务对象。等待该任务的任何形式(同步等待
wait()
方法或异步等待async
关键字)立即完成,因为任务>代码>对象已经完成。
没有拳击行为,因为
任务
是参考类型。相反,由于您正在创建参考类型的实例(查看task.pletedTask
的文档。换句话说,这不是缓存的实例)。请注意,此方法签名对于方法呼叫者有些混乱:它可能认为此方法正在执行I/O工作,但实际上它在做CPU绑定的工作。您应该清楚地记录这种行为,甚至更好地避免使用此签名。
在第三个示例中,您要求线程池进行一些工作,然后返回
任务
对象,代表您已卸载到线程池的正在进行的操作。任务
对象基本上是一个代理,您可以用来等待分配给线程池的工作负载。当方法返回时,您只是知道您已经要求线程池去做某件事,何时以及如何完成工作完全由运行时控制。呼叫代码通常等待完成任务。可以通过阻止线程(例如
wait()
)或在不阻止线程的情况下同步完成此操作(例如等待)In the first example your code executes synchronously. The calling thread calling the method is blocked, waiting for the method execution to complete before doing anything else.
In some cases this is fine (e.g. some scripting procedure you need to run in order to maintain a database), some other times this is an issue (e.g. server side code inside an ASP.NET core application in the controller code).
The second example is basically the same, but you are instead returning a completed task. The code still completes synchronously, there is no difference. The caller gets back an already completed task object. Any form of waiting on that Task (both synchronous wait with the
Wait()
method or asynchronous wait with theasync
keyword) completes immediately, because theTask
object is already completed.There is no boxing behavior involved, because
Task
is a reference type. There is instead allocation, because you are creating an instance of a reference type (check out the docs forTask.CompletedTask
. They clearly say that calling it multiple times is not guaranteed to always return the same instance, in other words it is not a cached instance).Notice that this method signature is somewhat confusing for the method caller: it may think that this method is doing I/O work, but it is actually doing CPU bound work. You should clearly document this behavior or even better avoid this signature at all if you can.
In the third example you are asking the thread pool to do some work, and you are returning a
Task
object representing the ongoing operation that you have offloaded to the thread pool. TheTask
object is basically a proxy that you can use to wait for the completion of the workload you have assigned to the thread pool.When the method returns you simply know that you have asked the thread pool to do something, when and how this work is done is totally under the control of the runtime. Calling code typically waits for the task to be completed. This can be done synchronously, by blocking the thread (e.g.
Wait()
) or asynchronously without blocking the thread (e.g.await
)在方法之外,应避免使用异步返回空隙,您不会在异步空隙方法中发现任何例外。
Returning void with async should be avoided cause outside of the method you will not catch any exceptions happening in async void method.
这取决于用法,如果您必须在其中调用一些异步操作,例如向API或DB提出请求,您可以具有
async Task
或或async void
。通常,异步只允许呼叫底部的任务在等待您的方法执行时没有任何变化。It depends on the usage, if you have to call some async operations in it like making request to an API or DB you can eighter have
async Task
orasync void
. Usually async just allows the tasks in the bottom of your call to be awaited nothing changes in the execution of your methods.