Pensé que entendía el patrón de espera asíncrona y la Task.Runoperación.
Pero me pregunto por qué en el siguiente ejemplo de código awaitno se sincroniza con el hilo de la interfaz de usuario después de regresar de la tarea finalizada.
public async Task InitializeAsync()
{
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}"); // "Thread: 1"
double value = await Task.Run(() =>
{
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}"); // Thread: 6
// Do some CPU expensive stuff
double x = 42;
for (int i = 0; i < 100000000; i++)
{
x += i - Math.PI;
}
return x;
}).ConfigureAwait(true);
Console.WriteLine($"Result: {value}");
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}"); // Thread: 6 - WHY??
}
Este código se ejecuta dentro de una aplicación .NET Framework WPF en un sistema Windows 10 con el depurador de Visual Studio 2019 adjunto.
Estoy llamando a este código desde el constructor de mi Appclase.
public App()
{
this.InitializeAsync().ConfigureAwait(true);
}
Quizás no sea la mejor manera, pero no estoy seguro de si esta es la razón del comportamiento extraño.
El código comienza con el hilo de la interfaz de usuario y debe hacer alguna tarea. Con la awaitoperación y una vez ConfigureAwait(true)finalizada la tarea, debe continuar en el subproceso principal (1). Pero no lo hace.
¿Por qué?
fuente

Respuestas:
Es algo complicado.
Estás llamando
awaital hilo de la interfaz de usuario, es cierto. ¡Pero! Lo estás haciendo dentroAppdel constructor.Recuerde que el código de inicio generado implícitamente se ve así:
El bucle de eventos, que se utiliza para volver al subproceso principal, se inicia solo como parte de la
Runejecución. Entonces, durante laAppejecución del constructor, no hay un bucle de eventos. Todavía.Como consecuencia, el
SynchronizationContext, que es técnicamente responsable del retorno del flujo al hilo principal despuésawait, estánullen el constructor de la aplicación.(
SynchronizationContextse capturaawaitantes de esperar, por lo que no importa que después de finalizarTaskya haya un valor válidoSynchronizationContext: el valor capturado esnull, por lo queawaitcontinúa la ejecución en un grupo de subprocesos).Entonces, el problema no es que esté ejecutando el código en un constructor, sino que lo está ejecutando en el
Appconstructor de S, momento en el cual la aplicación aún no está totalmente configurada para su ejecución. El mismo código enMainWindowel constructor se comportaría bien.Hagamos un experimento:
El primer resultado da
el segundo
Entonces puede ver que ya
OnStartuphay un contexto de sincronización. Así que si usted se mueveInitializeAsync()haciaOnStartup, se comportará como se espera también.fuente