How to use valuetask in c#

Time:2021-8-23

Asynchronous programmingI believe you have used it for many years, especially the await and async keywords introduced in c# 5.0 make the code easier and rough. You can use itAsynchronous programmingTo improve the performance of the applicationresponse speedandThroughput

The recommended method in asynchronous methods is to return the task. If some data needs to be returned in asynchronous methods, you canTaskChange toTask<T>In another case, your asynchronous method doesn’t need to return anything, so just change it to void.

Before c# 7.0, there were three types of return values for asynchronous methods.

  • Task
  • Task<T>
  • void

After c# 7.0, you can return in addition to the above threeValueTaskandValueTask<T>, these classes areSystem.Threading.Tasks.ExtensionsNamespace, I’m going to discuss valuetask with you in this article.

Why use valuetask

Task can be used to represent the status of an operation. What does it mean? For example: is this operation completed? Whether it is cancelled, etc. at the same time, task or valuetask can be returned in asynchronous methods. I don’t know if you have noticed a potential problem here, because task is a reference type, as shown in the following code:


    public class Task : IAsyncResult, IDisposable
    {
    }

This means that every time an asynchronous method is called, theManaged heapA task instance is generated on the. If it is called 1W times in an instant, there are 1W task instances on the managed heap in an instant. What’s the problem? The problem is that in some scenarios, your asynchronous method can directly return data, or it can be completely synchronized. For example, your asynchronous method only fetches data from the cache. At this time, it is not so beautiful to unnecessarily increase the recycling pressure on the GC.


        static Task<int> GetCustomerCountAsyc(string key)
        {
            return Task.FromResult<int>(NativeCache[key]);
        }

At this time, you need to use valuetask, which provides the following two benefits:

  • Valuetask is a value type, so it avoids memory allocation on the managed heap and has higher performance.
  • Valuetask is more convenient and flexible in implementation.

In general: if your asynchronous method can get results directly, it is recommended thatTask<T>Change toValueTask<T>To avoid unnecessary performance overhead,TaskandValueTaskThey are all operations that can wait. Note here that do not block valuetask. After all, it is a value type. If you really want to do so, call valuetask.astask method to convert valuetask into task, and then block the referenced task. Another note is that valuetask can only be blockedawaitOnce, if you want to break this restriction, you can call the astask method to turn valuetask into task.

Valuetask example

Suppose you have an asynchronous method that needs to return a task. You can use itTask.FromResultTo generate a task object, as shown in the following code:


public Task<int> GetCustomerIdAsync()
{
    return Task.FromResult(1);
}

The above code will not generate a complete state machine code at the IL level, but only a task object in the managed heap. To avoid this unnecessary task allocation, you can use valuetask to remove it, as shown in the following code:


public ValueTask<int> GetCustomerIdAsync()
{
    return new ValueTask(1);
}

Next, define an irepository interface and add a return value ofValueTask<int>The synchronization method of is shown in the following code:


    public interface IRepository<T>
    {
        ValueTask<T> GetData();
    }

Derive a repository class from the irepository interface, as shown in the following code:


    public class Repository<T> : IRepository<T>
    {
        public ValueTask<T> GetData()
        {
            var value = default(T);
            return new ValueTask<T>(value);
        }
    }

Finally, call the GetData method in main.


        static void Main(string[] args)
        {
            IRepository<int> repository = new Repository<int>();
            var result = repository.GetData();
            if(result.IsCompleted)
                 Console.WriteLine("Operation complete...");
            else
                Console.WriteLine("Operation incomplete...");
            Console.ReadKey();
        }

Now add an asynchronous method to the irepository interfaceGetDataAsync, the modified code is as follows:


    public interface IRepository<T>
    {
        ValueTask<T> GetData();
        ValueTask<T> GetDataAsync();
    }
    
    public class Repository<T> : IRepository<T>
    {
        public ValueTask<T> GetData()
        {
            var value = default(T);
            return new ValueTask<T>(value);
        }
        public async ValueTask<T> GetDataAsync()
        {
            var value = default(T);
            await Task.Delay(100);
            return value;
        }
    }

When should valuetask be used

Although valuetask provides many benefits, it must be weighed again and again to replace task with valuetask, because valuetask is a value type containing two fields, while task is only a reference type of one field, which means that returning valuetask from method will have the cost of two fields, which will be generated in await scenario at the same timeAsynchronous state machineMore space is needed to store the valuetask type of the two fields.

If extended, if the caller of the asynchronous method usesTask.WhenAllperhapsTask.WhenAnyThe return value of this asynchronous method isValueTaskIt usually costs more. Why do you say so? Because you have to convert valuetask into task to be used in whenxxx, the memory allocation of managed heap will be caused in this process. If you want to optimize, you can cache this instance when using task for the first time for subsequent reuse.

Finally, some conclusions are summarizedRule of thumbAll right.

  • If your asynchronous method is not immediate, use task.
  • If your asynchronous method can be completed immediately, such as pure memory operation and read cache, please use valuetask.

In any case, before using valuetask, you must do the necessary performance analysis and give yourself sufficient reasons to use valuetask.

Translation link: https://www.infoworld.com/art…

More high quality dry goods: see my GitHub: csharpranslate