Non capisco bene la differenza tra Task.Wait
e await
.
Ho qualcosa di simile alle seguenti funzioni in un servizio WebAPI ASP.NET:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Dove si Get
bloccherà.
Cosa potrebbe causare questo? Perché questo non causa problemi quando utilizzo un'attesa di blocco anziché await Task.Delay
?
Task.Delay(1).Wait()
è praticamente la stessa cosa di Thread.Sleep(1000)
. Nel codice di produzione effettivo è raramente appropriato.
WaitAll
causando il deadlock. Vedi il link al mio blog nella mia risposta per maggiori dettagli. Dovresti usare await Task.WhenAll
invece.
ConfigureAwait(false)
una sola chiamata per Bar
o Ros
non si bloccherà, ma perché hai un enumerabile che sta creando più di una e che sta aspettando su tutte quelle, la prima barra bloccherà la seconda. Se await Task.WhenAll
invece di attendere tutte le attività, in modo da non bloccare il contesto ASP, vedrai il metodo tornare normalmente.
.ConfigureAwait(false)
fino in fondo all'albero fino a quando non si blocca, in questo modo nulla sta mai cercando di tornare al contesto principale; avrebbe funzionato. Un'altra opzione sarebbe quella di creare un contesto di sincronizzazione interno. Link . Se lo metti Task.WhenAll
dentro, AsyncPump.Run
si bloccherà efficacemente tutto senza che tu ne abbia bisogno da ConfigureAwait
nessuna parte, ma probabilmente è una soluzione troppo complessa.
Task.Delay(1).Wait()
quale è abbastanza buono.