I have a situation where my code is waiting for some time delay:
await Task.Delay(10_000, cancellationToken);
Under some circumstances I want to continue immediately even if the timeout has not yet been expired ("shortcut the delay"). This decision can be taken while the code is already awaiting the Delay.
What I don't want to do: Loop on condition
foreach (var i = 0; i < 10 && !continueImmediately; i++)
{
await Task.Delay(1000, cancellationToken);
}
because it either has some latency (here 1 second) or wakes up unnecessarily.
What I also don't want to do: Cancel
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)
try
{
await Task.Delay(1000, linkedTokenSource.Token);
}
catch (OperationCancelledException)
{
// determine if the delay was cancelled by the cancellationToken or by the delay shortcut...
}
because I want to avoid exceptions.
What I came up with:
TaskCompletionSource tcs = new TaskCompletionSource();
await Task.WhenAny(new[] { tcs.Task, Task.Delay(10_000, cancellationToken) });
and to shortcut the delay: tcs.SetResult().
This seems to work but I an unsure if there is any cleanup missing. E.g. if the shortcut is taken (i.e. the WhenAny completes because of the tcs.Task), will the Task.Delay continue to consume resources?
Note: for sure I like cancellation support but this is not my question, so you may ignore all the cancellationTokens in my question.