A quick guide through Tasks and ValueTasks in C#

Asynchronous programming plays a vital role in modern software development, allowing us to efficiently utilize system resources and create responsive user interfaces. In the realm of C#, two powerful tools that facilitate asynchronous operations are Tasks and ValueTasks.

In this blog post, we’ll have a quick overview of Tasks and ValueTasks in C#. Prepare to optimize your code and unlock the full potential of asynchronous programming!

What is a task?
In short, a Task is a class that is used for asynchronous programming to execute a single operation. If the operation needs to return a result, the class Task<TResult> is used.

What is a ValueTask?
A ValueTask is a struct wrapper for the Task class. It basically has two fields, a field to store the Task/Task<TResult> and a field to store the TResult.

The difference
Since Task is a class, when it’s instantiated, it is stored on the heap. That means that, eventually, the garbage collector will be called to free the memory of the instantiated Task class after use.

ValueTask is a struct and, therefore, is stored on the stack. The benefit of this is that, as soon as the ValueTask is used, it is removed from the stack and that memory is freed.

When should ValueTask be used instead of Task?
ValueTask should be used only when you expect an asynchronous method to run synchronously most of the time.

In the image provided as part of this post, you can see the code and the benchmark results for the same operation performed by the Task and ValueTask. We can see that, in this case, less memory is used by using ValueTask.

There are a few guidelines to follow when using ValueTask:

  • ValueTask is a one-and-done deal. Don’t await the same ValueTask more than once as it may result in undefined behavior.
  • ValueTask cannot be used with WhenAny(), WhenAll() methods. For that to work, we have to convert the ValueTask into a Task using AsTask().
  • The same instance should not be awaited concurrently.

Tldr; ValueTask is good when used for asynchronous methods that will run synchronously most of the time since it can save memory. But it shouldn’t be awaited multiple times, it cannot be used with WhenAll(), WhenAny() methods and the same instance should not be awaited concurrently.

Hopefully this has been helpful to you.
However, if you still need expert help, leave us a message here and tell us what’s bothering you.

Related Posts

Leave a Reply

Contact Us