Create a Completed Task

Create a completed Task

The newest version of .Net (v4.6) is adding just that, a built-in Task.CompletedTask:

Task completedTask = Task.CompletedTask;

That property is implemented as a no-lock singleton so you would almost always be using the same completed task.

Create a completed TaskT

private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
var taskSource = new TaskCompletionSource<Result>();
taskSource.SetResult(theResult);
return taskSource.Task;
}

await Task.CompletedTask vs return

Let's look the question from the consumer-side.

If you define an interface, which imposes an operation that returns a Task then you don't say anything about how it will be calculated / executed (so, there is no async access modifier in the method signature). It is an implementation detail.

Interface

public interface ITest
{
Task Test();
Task<bool> IsTest();
}

So, it is up to you how you implement the interface.

You can do it in a synchronous way, when there won't be any AsyncStateMachine generated because of the absence of the async keyword.

Implementation #1

public class TestImpl : ITest
{
public Task Test()
{
return Task.CompletedTask;
}

public Task<bool> IsTest()
{
return Task.FromResult(true);
}
}

Or you can try to implement it in an asynchronous way but without await operators. Here you will receive CS1998 warnings.

Implementation #2

public class TestImpl : ITest
{
public async Task Test()
{
return;
}

public async Task<bool> IsTest()
{
return true;
}
}

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

In other words this implementation does not define a state machine. An async method is divided into different states based on the await keywords:

  • before_the_await_1,
  • after_the_await_1_but_before_the_await_2
  • after_the_await_2_but_before_the_await_3
  • ...

If you haven't got any await then you would have a single state, which would run in sync (there is no need to preserve state, execute async operation and then call MoveNext()).


Or you can try to implement it in an asynchronous way with await operators.

Implementation #3

public class TestImpl : ITest
{
public async Task Test()
{
await Task.CompletedTask;
}

public async Task<bool> IsTest()
{
return await Task.FromResult(true);
}
}

In this case there will be an async state machine but it won't be allocated on the heap. By default it is a struct and if it finishes in sync then we don't need to allocate them on the heap to extend its life out of the scope of the method.

For further information please read these articles:

  • Async/await in .NET Core 3.x
  • Async ValueTask Pooling in .NET 5
  • Dissecting the async methods in C#

How to create a Task I can complete manually

You can use a TaskCompletionSource to create a fully 'manual' task.

Represents the producer side of a Task unbound to a delegate,
providing access to the consumer side through the Task property.

Hand out the the completion source's Task property to the consumer, and call SetResult on it (at will) to complete the task. Note that you also have SetCanceled and SetException to represent cancellations and failures, respectively.

What's the most concise way to create a Task that never returns?

You can use:

var taskThatNeverReturns = Task.Delay(Timeout.Infinite);

The docs states that the parameter represents:

The number of milliseconds to wait before completing the returned task, or -1 to wait indefinitely.

Timeout.Infinite is a constant field with a value of -1.

What is the ValueTask equivalent of Task.CompletedTask?

All structs have a default constructor. The default constructor of ValueTask creates a completed ValueTask:

var completedValueTask = new ValueTask();

Or alternatively:

ValueTask completedValueTask = default;

Update: The official documentation has been updated with the following note:

An instance created with the parameterless constructor or by the default(ValueTask) syntax (a zero-initialized structure) represents a synchronously, successfully completed operation.

Does await Task.CompletedTask mean the async method will run synchronously?

Yes, this code will always run synchronously; the main continuation compiler goo is only invoked when the first incomplete awaitable is encountered.

You can see this in sharplab - in particular, here:

awaiter = Task.CompletedTask.GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (<>1__state = 0);
<>u__1 = awaiter;
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
return;
}

It is the AwaitUnsafeOnCompleted(...) + return that implements asynchronicity.

If my interface must return Task what is the best way to have a no-operation implementation?

Today, I would recommend using Task.CompletedTask to accomplish this.


Pre .net 4.6:

Using Task.FromResult(0) or Task.FromResult<object>(null) will incur less overhead than creating a Task with a no-op expression. When creating a Task with a result pre-determined, there is no scheduling overhead involved.



Related Topics



Leave a reply



Submit