Reputation: 1920
I have the following code (yes, I could be simulating JavaScript setTimeout
api)
async void setTimeout(dynamic callback, int timeout)
{
await Task.Delay(timeout);
callback();
}
It looks like for timeout > 0
, the setTimeout
works asynchronously wherein the control is returned back to the callee
on await
and callback
is invoked after the task runs asynchronously. BUT when timeout == 0
, the function behaves in a synchronous manner (code always run past the await line in the same thread without a context switch). On further digging, it turns out that Task.Delay
is implemented to behave this way (Task.Yield() versus Task.Delay(0))
Wondering if there is a way to make Task.Delay(0) asynchronous or an alternate solution to make my setTimeout
function asynchronous when timeout
is 0
? (so that I could mimic JavaScript setTimeout
functionality) I see discussions on using Task.FromResult(true)
or Task.WhenAll
, but they don't seem to work.
Indeed I can use Task.Delay(1)
instead of Task.Delay(0)
but it does not look organic.
Upvotes: 18
Views: 12176
Reputation: 13495
The reason Task.Delay(0)
does not run asynchronously is because the async-await state machine explicitly checks whether the task is completed and if it is, it runs synchronously.
You can try using Task.Yield(), which will force the method to return immediately and resume the rest of the method on the current SynchornizationContext
. eg:
async void setTimeout(dynamic callback, int timeout)
{
if(timeout > 0)
{
await Task.Delay(timeout);
}
else
{
await Task.Yield();
}
callback();
}
Upvotes: 26