Create a Completed Task<T>

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;
}

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.

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#

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.

How does Task.CompletedTask work with thread pool?

the meaning of Task is to let a worker thread in the thread pool to run it,

Running code on the thread pool is one way in which Tasks manifest themselves.

Other ways to create Tasks are to write async methods and to use Task.CompletedTask1 or Task.FromResult<TResult>2.

Just because Task.Run causes code to run on the thread pool does not mean that these other uses of Task must also necessarily involve the thread pool.

For Task.CompletedTask, especially, this is "I've already done the work required, but I want to present it to other code as a Task. No additional code runs anywhere.

We can see in the reference source that this property just returns the task:

    /// <summary>A task that's already been completed successfully.</summary>
private static Task s_completedTask;

/// <summary>Gets a task that's already been completed successfully.</summary>
/// <remarks>May not always return the same instance.</remarks>
public static Task CompletedTask
{
get
{
var completedTask = s_completedTask;
if (completedTask == null)
s_completedTask = completedTask = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); // benign initialization ----
return completedTask;
}
}

1As shown in the reference source later though, we often aren't even creating a new Task here, just reusing an existing one. But the team have obviously decided to forgo thread-safe initialisation of the property in favour of documenting that they won't guarantee to always return the same Task.

2These latter two are quite similar, in that they represent "I've already done the work required, now for some reason I need to pass some other code a Task"3.

3Often, and I'm guessing as is the case here, when you're implementing an interface or overriding a base class method that is Task returning but your code is fast and synchronous so you have no need to be async.

Why returning Task.CompletedTask failed to compile in an async method?

Your method could functionally be condensed down to this.

public static Task F() 
{
return Task.Delay(1000);
}

Returning an Task.CompletedTask instance is only useful if these apply:

  • you do not want to use async/await
  • your method returns a Task (effectively void if you were to make it not asynchronous)
  • your code has logic where a task might not be returned

Example:

public static Task F() 
{
if (someConditionToShortCircutTheMethod)
return Task.CompletedTask;

// rest of logic
return Task.Delay(1000);
}

As soon as you make your method async then the fact that a Task is actually being returned is abstracted. This can make the code easier to work with especially if there are multiple points where the code waits for I/O operations to complete.

public static async Task F() 
{
if (someConditionToShortCircutTheMethod)
return;

// rest of logic
await Task.Delay(1000);
await Task.Delay(1000);
// no return necessary, async Task has a similar flow as return type void
}

I also recommend reviewing these previous questions:

  • How and when to use ‘async’ and ‘await’
  • Understanding async / await in C#

await Task.CompletedTask for what?

It is there to make it easier for later stage to implement async code calls without having to alter the signature thus preventing having to refactor the calling code.

Whilst the scaffolded sample code is synchronous, the Template Studio is designed specifically around an async data access layer, you are expected to implement your own data access by modifying the body of the generated methods.

If the async implementation were NOT implemented, there would be significant code changes throughout the templated app and it would be a very steep learning curve for new developers, the point of the template is to get up and running with minimal effort or even experience!

Another option would be to remove the async keyword from the method signature and that line and do

return Task.FromResult<IEnumerable<SampleModel>>(data); 

You see this construct when you need to return an awaitable Task due to an interface for example while the implementation has no async work to do.

In this case however, since it is a template they expect people to replace the await Task.Completed with something like await FetchDataFromDatabaseAsync();. Since the async keyword is already there it minimizes the needed changes to implement your own async call.

Anyway, without this await construct you can do this:

public class SampleModelService
{
public Task<IEnumerable<SampleModel>> GetDataAsync()
{
var data = new List<SampleModel>();

data.Add(new SampleModel
{
Title = "Lorem ipsum dolor sit 1",
Description = "Lorem ipsum dolor sit amet",
Symbol = Symbol.Globe
});

data.Add(new SampleModel
{
Title = "Lorem ipsum dolor sit 2",
Description = "Lorem ipsum dolor sit amet",
Symbol = Symbol.MusicInfo
});

return Task.FromResult<IEnumerable<SampleModel>>(data);
}
}

If there is no requirement to return a Task at all (you do not have any async code) then just remove it completely. (But then you have to refactor code that calls this method)

Reviewing this code I suspect someone is going to call an async method later in the development process and already anticipated that by specifying that this method returns a Task.

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.

What is an alternative for Task.FromResultT() for tasks that represent operations returning void

Task<T> extends Task - so it's reasonably common to just use Task.FromResult<object> and provide an empty result. For example:

Task ret = Task.FromResult<object>(null);

(Or use a value type - it really doesn't matter much.)

Of course, as tasks are immutable you could create a singleton instance of this and return it every time you want to return a completed task. (I believe that's what the async/await infrastructure does, in fact - or at least did in beta releases...)

As Asad noted, you can use Task.CompletedTask, but only if you're targeting .NET 4.6. (Actually, it's not clear whether it's supporting in .NET 4.5 or not - the documentation shows ".NET Framework 4.6 and 4.5" as the version number, but then says "Supported in: 4.6"...)



Related Topics



Leave a reply



Submit