ValueTaskSupplement, an extensions to ValueTask
I have released the new ValueTaskSupplement library.
https://github.com/Cysharp/ValueTaskSupplement
This release adds WhenAny, WhenAll, and Lazy to ValueTask.
The need for this library can be understood from the relationship between Task and ValueTask, and the appearance of IValueTaskSource.
Task and ValueTask
When async/await were first introduced in C# 5.0, only Task was available. Through great effort by Microsoft, such as the addition of the async method to standard APIs, C# ushered in the asynchronous age ahead of other languages (in 2012), and async/await saw considerable use. However, as a result of heavy use, I noticed that Task incurred greater overhead than expected, particularly in matching interfaces, with the result that in many situations it only wrapped the synchronous method. A measure to address the performance issue appeared in C# 7.0 as ValueTask.
At the time of its appearance, ValueTask was T | Task [T], which wrapped T if the content was synchronous, and Task if asynchronous. Therefore, the proper use of Task vs. ValueTask was considered to be based on Task conforming to the standard definition, with wrapping unnecessary when the content is confirmed to be asynchronous.
In the pursuit of further performance, IValueTaskSource was introduced to eliminate the overhead of ValueTask-> Task conversion, and to insert code specialized for particular content. With this, ValueTask becomes a union that has one of the states of T | Task [T] | IValueTaskSource, and in individually implemented scenarios, performance is higher when the content is IValueTaskSource than when it is Task [T]. Accordingly, the era of ValueTask has arrived, in both name and reality.
Latest coreclr draft(2019–08–22), Make “async ValueTask/ValueTask<T>” methods ammortized allocation-free will change the common sense of Task and ValueTask.
In actual adoption in applications, it is nearly impossible to think through the proper separation of use every time, and as a basic rule, it is necessary to lay out rules that standardize on one of the two in principle. The appearance of IValueTaskSource should become a major tailwind behind the standardization on ValueTask.
The UniTask library that I created exists in Unity. This is a close substitute for ValueTask + IValueTaskSource.
Lack of ValueTask
The greatest flaw in ValueTask is the lack of utility. In other words, there is nothing corresponding to Task.WhenAll and Task.WhenAny, and when these are necessary, conversion to Task with AsTask was required. This is troublesome even for the API, and the conversion to Task naturally incurs overhead.
Therefore, based on the idea that using IValueTaskSource to create native WhenAll and WhenAny for ValueTask should achieve both an easy-to-use API and high performance, ValueTaskSupplement offers this.
Functions that are even more convenient than just Task.WhenAll/WhenAny, such as WhenAll with different types that depend on tuple, have been added, which should make it easy to standardize on ValueTask.
I hope you will give ValueTaskSupplement a try.