2015-10-29 2 views
5

У меня есть следующий код (да, я мог бы имитировать JavaScript setTimeout API)Task.Delay (0) не асинхронный

async void setTimeout(dynamic callback, int timeout) 
    { 
     await Task.Delay(timeout); 
     callback(); 
    } 

Похоже на timeout > 0, то setTimeout работает асинхронно, в котором управление возвращается обратно к callee по await и callback вызывается после выполнения задачи асинхронно. BUT, когда timeout == 0, функция ведет себя синхронно (код всегда проходит мимо строки ожидания в том же потоке без контекстного переключателя). При дальнейшем копания, оказывается, что Task.Delay осуществляется вести себя таким образом (Task.Yield() versus Task.Delay(0))

интересно, если есть способ сделать Task.Delay (0) асинхронно или альтернативное решение, чтобы сделать мою setTimeout функцию асинхронно, когда timeout является 0? (, чтобы я мог имитировать JavaScriptsetTimeoutфункциональность) Я вижу обсуждения об использовании Task.FromResult(true) или Task.WhenAll, но они, похоже, не работают.

Действительно, я могу использовать Task.Delay(1) вместо Task.Delay(0), но он не выглядит органичным.

+0

Что вы ищете, когда говорите, что ищете «контекстный переключатель»? –

+0

Я не совсем уверен, чего вы пытаетесь достичь. Если вы задерживаете '0ms', вы не задерживаетесь. На самом деле, он не является ни синхронным, ни асинхронным, поскольку это, по сути, не-op. Существует буквально *** никакой работы ***, которая должна выполняться асинхронно, поэтому она немедленно возвращается. – Rob

+4

Используйте 'Task.Yield'. Это опубликует продолжение, которое нужно обработать, однако TaskScheduler считает нужным, что демонстрирует это другое сообщение. Если вы хотите заставить новый поток использовать 'Task.Delay (timeout) .ConfigureAwait (false)'. –

ответ

9

Причина, по которой Task.Delay(0) не работает асинхронно, заключается в том, что машина состояния асинхронного ожидания явно проверяет, завершена ли задача и если она есть, она выполняется синхронно.

Вы можете попробовать использовать Task.Yield(), что заставит метод немедленно вернуться и возобновить оставшуюся часть метода в текущем SynchornizationContext. например:

async void setTimeout(dynamic callback, int timeout) 
{ 
    if(timeout > 0) 
    { 
     await Task.Delay(timeout); 
    } 
    else 
    { 
     await Task.Yield(); 
    } 

    callback(); 
} 
+0

, пожалуйста, исправьте свою часть. его не завершено. где находится Task.Yield? ;) –

+0

спасибо, не уверен, что произошло, он как-то потерялся после моего входа. –

+2

Это условие гонки, которое все равно может вызвать синхронное поведение, если 'timeout' очень низкий. Я рекомендую использовать 'waitait Task.Yield(); ожидание Task.Delay (тайм-аут); '. –

Смежные вопросы