Is there still a benefit in returning ValueTask if I use TaskCompletionSource to implement actual asynchrony?
As I understand it, the purpose of ValueTask is to reduce allocations, but allocations are still there when awaiting TaskCompletionSource.Task. Here is a simple example to illustrate the question:
async ValueTask DispatcherTimerDelayAsync(TimeSpan delay)
{
var tcs = new TaskCompletionSource<bool>();
var timer = new DispatcherTimer();
timer.Interval = delay;
timer.Tick += (s, e) => tcs.SetResult(true);
timer.Start();
try
{
await tcs.Task;
}
finally
{
timer.Stop();
}
}
Should I rather be returning Task (versus ValueTask) from DispatcherTimerDelayAsync, which itself is always expected to be asynchronous?
There are pros and cons of each. In the "pro" column:
Task<T>), using ValueTask<T> avoids an allocation of the task - however, this doesn't apply for "void" (i.e. non-generic Task), since you can just return Task.CompletedTask
(a special-case of "2" might be amortization via tools like PooledAwait)
It doesn't feel like either of those apply here, but: if in doubt, remember that it is allocation-free to return a Task as a ValueTask (return new ValueTask(task);), which would allow you to consider changing the implementation to an allocation-free one later without breaking the signature. You still pay for the original Task etc of course - but exposing them as ValueTask doesn't add any extra.
In all honesty, I'm not sure I'd worry too much about this in this case, since a delay is ways going to be allocatey.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With