Is having a return type of Task enough to make a method run asynchronously?

大城市里の小女人 提交于 2020-06-09 07:10:20

问题


I have a simple method that does a complicated string operation and returns the result. As you can see, the return type of this method is Task<string>. Therefore, I can use Task.FromResult(result) to return the value of my string.

public Task<string> ComplexOperation()
{
    string result = // Do something complex
    return Task.FromResult(result);
}

Then, I can use the await keyword to call this method.

public static async Task Main(string[] args)
{
    var myResult = await ComplexOperation();
}

Because I am awaiting CompelxOperation(), (waiting for the Task to return on completion) will this method run asynchronously?


回答1:


Based on your comments you need to do something like this:

public Task<string> ComplexOperation()
{
    return Task.Run(() =>  /* Do something complex */);
}

You can play with it like this:

public static async Task Main()
{
    Console.WriteLine("Before" );
    var myResultTask = ComplexOperation();
    Console.WriteLine("After task creation");
    var result = await myResultTask;
    Console.WriteLine("After async await");
}

public Task<string> ComplexOperation()
{    
    Console.WriteLine("Creation");
    return Task.Run(() =>
    {
        Console.WriteLine("In before work");
        Thread.Sleep(500); //simulate work;
        Console.WriteLine("In after work");
        return "Done";
    });
}

And compare the behavior with switching to your implementation when you just return Task.FromResult. Also it does not makes much sense in such test example, TBH.




回答2:


Just as you flagged as async the Main method to get an asynchronous method you need to flag the method as asynchronous with the async keyword, and make the result a Task.

But in the framework Tasks are used for 2 related but different concepts, parallelization and asynchronous programming.

What you are doing is use parallelization.

So you are just running some synchronous code on a different thread.

Based on your example i think what you need is to use parallelization, which can speed up some complex calculation or work by use many threads to work in parallel.

The concept behind asynchronous code is to free the thread while you are waiting for external resources (like some data from a web service), to allow other work to be done in the meantime.

So, if you need to do complex work with local resources it's better use tasks without async logic, instead when working with remote resources you can go for asynchronous operations.




回答3:


Semantically the method ComplexOperation is asynchronous because it returns an awaitable type, and in order to follow the guidelines it should be named ComplexOperationAsync.

Asynchronous methods in TAP include the Async suffix after the operation name for methods that return awaitable types, such as Task, Task<TResult>, ValueTask, and ValueTask<TResult>.

But it is not a well behaved asynchronous method. An asynchronous method is expected to return an incomplete Task immediately, allowing the caller to await the task asynchronously without been blocked. From the docs:

An asynchronous method that is based on TAP can do a small amount of work synchronously, such as validating arguments and initiating the asynchronous operation, before it returns the resulting task. Synchronous work should be kept to the minimum so the asynchronous method can return quickly.

The ComplexOperation method does exactly the opposite: it forces the calling thread to perform the complex operation, and finally it hands back a completed task. For all intents and purposes this operation is not asynchronous at all. It is 100% synchronous and 0% asynchronous, plus some overhead (to add insult to injury). So don't do this, and if there is some library that does it, don't use the library. It is simply bad practice.


Clarification: Since the term asynchronous method can mean different things in different contexts, I should clarify that the context of this answer is the perspective of the consumer, who sees the signature of the method as a contract, and builds expectations based on the visible contract and not on the invisible implementation. In this context the method ComplexOperation is asynchronous. If we switch perspective and focus on the implementation, the method ComplexOperation is not asynchronous. My statement «it is simply bad practice» refers to the practice of breaking the contract, and providing a synchronous implementation to a method with asynchronous contract. I am not criticizing the use of Task.FromResult method per se. I am criticizing it only when it follows a complex/lengthy/latent operation, that according to the method's contract should be made asynchronous.

P.S. I am thankful to @DmytroMukalov for providing (in the chat) the helpful distinction between asynchrony by contract and by implementation.



来源:https://stackoverflow.com/questions/61837259/is-having-a-return-type-of-task-enough-to-make-a-method-run-asynchronously

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!