555

In the code below, due to the interface, the class LazyBar must return a task from its method (and for argument's sake can't be changed). If LazyBars implementation is unusual in that it happens to run quickly and synchronously - what is the best way to return a No-Operation task from the method?

I have gone with Task.Delay(0) below, however I would like to know if this has any performance side-effects if the function is called a lot (for argument's sake, say hundreds of times a second):

  • Does this syntactic sugar un-wind to something big?
  • Does it start clogging up my application's thread pool?
  • Is the compiler cleaver enough to deal with Delay(0) differently?
  • Would return Task.Run(() => { }); be any different?

Is there a better way?

using System.Threading.Tasks;

namespace MyAsyncTest
{
    internal interface IFooFace
    {
        Task WillBeLongRunningAsyncInTheMajorityOfImplementations();
    }

    /// <summary>
    /// An implementation, that unlike most cases, will not have a long-running
    /// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations'
    /// </summary>
    internal class LazyBar : IFooFace
    {
        #region IFooFace Members

        public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
        {
            // First, do something really quick
            var x = 1;

            // Can't return 'null' here! Does 'Task.Delay(0)' have any performance considerations?
            // Is it a real no-op, or if I call this a lot, will it adversely affect the
            // underlying thread-pool? Better way?
            return Task.Delay(0);

            // Any different?
            // return Task.Run(() => { });

            // If my task returned something, I would do:
            // return Task.FromResult<int>(12345);
        }

        #endregion
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            Test();
        }

        private static async void Test()
        {
            IFooFace foo = FactoryCreate();
            await foo.WillBeLongRunningAsyncInTheMajorityOfImplementations();
            return;
        }

        private static IFooFace FactoryCreate()
        {
            return new LazyBar();
        }
    }
}
Jon Rea
  • 9,337
  • 4
  • 32
  • 35

9 Answers9

785

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.

Servy
  • 202,030
  • 26
  • 332
  • 449
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
204

To add to Reed Copsey's answer about using Task.FromResult, you can improve performance even more if you cache the already completed task since all instances of completed tasks are the same:

public static class TaskExtensions
{
    public static readonly Task CompletedTask = Task.FromResult(false);
}

With TaskExtensions.CompletedTask you can use the same instance throughout the entire app domain.


The latest version of the .Net Framework (v4.6) adds just that with the Task.CompletedTask static property

Task completedTask = Task.CompletedTask;
Community
  • 1
  • 1
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • Do I need to **return** it or **await** on it? – Egor Okhterov Aug 03 '15 at 16:06
  • @Pixar what do you mean? You can do both, but awaiting it will continue synchronously. – i3arnon Aug 03 '15 at 16:49
  • Sorry, I had to mention the context :) As I see it now, we can make `public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()` as well as `public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()`. So, we can either `return CompletedTask;` or `await CompletedTask;`. What is more preferrable (maybe more efficient or more congruent)? – Egor Okhterov Aug 03 '15 at 19:50
  • @Pixar no async would be more efficient. And anyways, if you do choose async then you don't need a completed task to begin with (`async Task DoAsync() { }`); – i3arnon Aug 03 '15 at 19:59
  • So, that should be the answer to the Jon's question? – Egor Okhterov Aug 03 '15 at 20:08
  • 5
    @Pixar I wan't clear. I meant "'no-async' would be more efficient". Making a method async instructs the compiler to transform it into a state-machine. It will also create a new task each time you call it. Returning an already completed task would be clearer and more performant. – i3arnon Aug 03 '15 at 20:11
  • Just out of curiosity, how would caching the resolved task affect performance? – Asad Saeeduddin Aug 07 '15 at 09:46
  • 3
    @Asad it reduces allocations (and with it GC time). Instead of allocation new memory and constructing a Task instance each time you need a completed Task, you only do this once. – i3arnon Aug 07 '15 at 09:48
  • @AlexZhukovskiy [it doesn't](http://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,11a386e7d7cae64a) and it can't, that will basically be a memory leak as it can't know how many possible values it may receive. Caching 2 tasks for `true` and `false` is fine, but caching 4 billion for `int` is quite problematic. – i3arnon May 18 '16 at 11:34
  • @i3arnon it's not done yet, but [it will be implemented](https://github.com/dotnet/corefx/issues/7798). – Alex Zhukovskiy May 18 '16 at 11:36
  • @AlexZhukovskiy 1. That's a different API. `Task.FromResult` will still not cache. 2. It's a suggestion, it doesn't mean it will be implemented. – i3arnon May 18 '16 at 11:37
  • @AlexZhukovskiy I have. There is zero chance `Task.FromResult` will cache everything. It will **maybe** cache a few common values like `true`, `false`, `0` and some other default values. – i3arnon May 18 '16 at 11:40
  • Better to call this TaskConstant as it'll clash with System.Threading.Tasks.TasksExtensions. – arviman Oct 24 '16 at 13:03
44

Task.Delay(0) as in the accepted answer was a good approach, as it is a cached copy of a completed Task.

As of 4.6 there's now Task.CompletedTask which is more explicit in its purpose, but not only does Task.Delay(0) still return a single cached instance, it returns the same single cached instance as does Task.CompletedTask.

The cached nature of neither is guaranteed to remain constant, but as implementation-dependent optimisations that are only implementation-dependent as optimisations (that is, they'd still work correctly if the implementation changed to something that was still valid) the use of Task.Delay(0) was better than the accepted answer.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 1
    I'm still using 4.5 and when I did some research I was amused to find that Task.Delay(0) is special cased to return a static CompletedTask member. Which I then cached in my own static CompletedTask member. :P – Darren Clark Jan 20 '16 at 22:43
  • 2
    I don't know why, but `Task.CompletedTask` can't be used in PCL project, even if I set the .net version to 4.6 (profile 7), just tested in VS2017. – Felix Mar 09 '17 at 08:12
  • @Fay I'd guess it must not be part of the PCL API surface, though the only thing do anything with at the moment that supports PCL also supports 4.5 so I'm already having to use my own `Task.CompletedTask => Task.Delay(0);` to support that, so I don't know for sure off the top of my head. – Jon Hanna Mar 09 '17 at 10:01
37
return Task.CompletedTask; // this will make the compiler happy
Xin
  • 33,823
  • 14
  • 84
  • 85
  • 1
    `return` didn't work for me - for an `async` Task, I had to just use `await Task.CompletedTask`. – dylanh724 Jun 21 '22 at 03:13
  • @dylanh724 I think it depends on your function definition, the original question requires returns something, so `return Task.CompletedTask` should help. However, if your function definition prob return void, then you can `await` – Xin Jun 21 '22 at 11:56
29

Recently encountered this and kept getting warnings/errors about the method being void.

We're in the business of placating the compiler and this clears it up:

    public async Task MyVoidAsyncMethod()
    {
        await Task.CompletedTask;
    }

This brings together the best of all the advice here so far. No return statement is necessary unless you're actually doing something in the method.

Alexander Trauzzi
  • 7,277
  • 13
  • 68
  • 112
  • 27
    That is completely wrong. You are getting a compiler error because the method definition contains async, so the compiler expects an await. The "correct" usage would be public Task MyVoidAsyncMethog() { return Task.CompletedTask;} – Keith Jan 26 '17 at 14:51
  • 3
    Not sure why this was down voted as this seems to be the cleanest answer – webwake Apr 27 '17 at 14:06
  • 4
    Because of Keith's comment. – noelicus Jun 07 '17 at 13:27
  • 5
    He isn't totally wrong, he's just removed the async keyword. My approach is more idiomatic. His is minimalistic. If not a bit rude. – Alexander Trauzzi Jun 07 '17 at 20:48
  • 4
    This makes no sense, completely agree with Keith here, I don't get all the upvotes actually. Why would you add code that is not necessary? `public Task MyVoidAsyncMethod() {}` is completely the same as above method. If there is a usecase for using it like this, please add the additional code. – Nick N. May 18 '18 at 13:14
  • My usecase was 'public async Task MyVoidAsyncMethod() { #if !DEBUG ..DoStuff ... #endif await Task.CompletedTask; }' – Peter Bruins Sep 27 '18 at 12:08
  • 1
    To avoid the void warning. Unless they've updated the compiler to stop doing this. – Alexander Trauzzi Sep 29 '18 at 13:08
15

When you must return specified type:

Task.FromResult<MyClass>(null);
trashmaker_
  • 151
  • 1
  • 2
2

I prefer the Task completedTask = Task.CompletedTask; solution of .Net 4.6, but another approach is to mark the method async and return void:

    public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
    {
    }

You'll get a warning (CS1998 - Async function without await expression), but this is safe to ignore in this context.

Remco te Wierik
  • 1,436
  • 2
  • 10
  • 10
-1

If you are using generics, all answer will give us compile error. You can use return default(T);. Sample below to explain further.

public async Task<T> GetItemAsync<T>(string id)
            {
                try
                {
                    var response = await this._container.ReadItemAsync<T>(id, new PartitionKey(id));
                    return response.Resource;
                }
                catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
                {

                    return default(T);
                }

            }
Karthikeyan VK
  • 5,310
  • 3
  • 37
  • 50
-1
return await Task.FromResult(new MyClass());
J.M.H
  • 67
  • 3
  • 5
    While this code may solve the question, [including an explanation](https://meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – David Buck Jun 02 '20 at 15:01