Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should methods returning Task<T> always start the returned task?

If I have a method like

Task<bool> LongProcessTaskAsync();

Would it be a better practice to return a started task

return Task<bool>.Factory.StartNew(() => { ... });

or just return new Task<bool>(() => ...)

Personally, I prefer the first method but I'd rather be consistent will other API's and libraries.

Is returning a not-started task ever more appropriate?

like image 783
karl.r Avatar asked Jul 29 '12 04:07

karl.r


People also ask

What happens when a method returns a Task without awaiting it?

An exception that's raised in a method that returns a Task or Task<TResult> is stored in the returned task. If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call.

What does a Task method return?

Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value.

How do I return a new Task in C#?

The recommended return type of an asynchronous method in C# is Task. You should return Task<T> if you would like to write an asynchronous method that returns a value. If you would like to write an event handler, you can return void instead. Until C# 7.0 an asynchronous method could return Task, Task<T>, or void.

Can we use return in Task?

Whatever you return from async methods are wrapped in a Task . If you return no value(void) it will be wrapped in Task , If you return int it will be wrapped in Task<int> and so on.


1 Answers

In the case of async/await methods, the Task will already be started. AFAIK, all the BCL methods added for Task-based versions return already-started Tasks. It would be kinda weird not to, since the common consumer case is now:

var foo = await GetFooAsync();

[EDIT] Based on Stephen pointing out that the TAP guidelines covers this (and he already includes a link to the guidelines), I'll include a quote of the relevant bit from page 4 (in The Task-based Asynchronous Pattern Defined -> Behavior -> Task Status), and I've added bold+italics around the key parts.

Task Status

The Task class provides a life cycle for asynchronous operations, and that cycle is represented by the TaskStatus enumeration. In order to support corner cases of types deriving from Task and Task as well as the separation of construction from scheduling, the Task class exposes a Start method. Tasks created by its public constructors are referred to as “cold” tasks, in that they begin their life cycle in the non-scheduled TaskStatus.Created state, and it’s not until Start is called on these instances that they progress to being scheduled. All other tasks begin their life cycle in a “hot” state, meaning that the asynchronous operations they represent have already been initiated and their TaskStatus is an enumeration value other than Created.

All tasks returned from TAP methods must be “hot.” If a TAP method internally uses a Task’s constructor to instantiate the task to be returned, the TAP method must call Start on the Task object prior to returning it. Consumers of a TAP method may safely assume that the returned task is “hot,” and should not attempt to call Start on any Task returned from a TAP method. Calling Start on a “hot” task will result in an InvalidOperationException (this check is handled automatically by the Task class).

like image 198
James Manning Avatar answered Sep 19 '22 13:09

James Manning