2015-10-29 12 views
5

ho il seguente codice (sì, potrei essere simulando JavaScript setTimeout api)Task.Delay (0) Non asincrona

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

Sembra per timeout > 0, i setTimeout opere in modo asincrono in cui il controllo è restituito di nuovo a callee su await e callback viene richiamato dopo che l'attività viene eseguita in modo asincrono. MA quando timeout == 0, la funzione si comporta in modo sincrono (il codice scorre sempre oltre la linea di attesa nella stessa thread senza un interruttore di contesto). Su ulteriore scavo, si scopre che Task.Delay è implementata a comportarsi in questo modo (Task.Yield() versus Task.Delay(0))

sapere se c'è un modo per rendere Task.Delay (0) asincrono o una soluzione alternativa per rendere la funzione setTimeout asincrona quando è timeout0? (in modo da poter simulare JavaScriptsetTimeoutfunzionalità) Vedo discussioni sull'utilizzo di Task.FromResult(true) o Task.WhenAll, ma non sembrano funzionare.

Infatti, posso usare Task.Delay(1) anziché Task.Delay(0) ma non sembra organico.

+0

Che cosa stai cercando quando dici che stai cercando un "interruttore di contesto"? –

+0

Non sono proprio sicuro di cosa stai cercando di ottenere. Se si fa ritardare per '0ms', non si sta davvero ritardando. In realtà, non è né sincrono né asincrono poiché è essenzialmente un no-op. Non c'è letteralmente niente lavoro da fare in modo asincrono, quindi ritorna immediatamente. – Rob

+4

Utilizzare 'Task.Yield'. Questo posterà la continuazione da gestire, tuttavia il TaskScheduler lo ritiene opportuno, come dimostrano altri post. Se vuoi forzare un nuovo thread usa 'Task.Delay (timeout) .ConfigureAwait (false)'. –

risposta

9

Il motivo Task.Delay(0) non viene eseguito in modo asincrono poiché la macchina di stato attendente asincrona controlla esplicitamente se l'attività è completata e, in caso affermativo, viene eseguita in modo sincrono.

È possibile provare a utilizzare Task.Yield(), che imporrà immediatamente il metodo di ritornare e riprendere il resto del metodo sull'attuale SynchornizationContext. es .:

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

    callback(); 
} 
+0

per favore aggiusta la tua parte. non è stato completato. dov'è Task.Yield? ;) –

+0

grazie, non sono sicuro di cosa sia successo, in qualche modo si è perso dopo l'accesso. –

+2

Questo ha una condizione di competizione che potrebbe comunque causare un comportamento sincrono se il timeout è molto basso. Consiglio di utilizzare 'wait Task.Yield(); attendere Task.Delay (timeout); '. –

Problemi correlati