2012-07-03 15 views
24

Estoy intentando cargar y leer un archivo de configuración en el inicio de la aplicación, y el 90% de las veces, el await GetFileAsync("filename.xml"); nunca regresa, por lo tanto, colgando la aplicación .Llamada a la espera GetFileAsync() nunca regresa y la aplicación se bloquea en la aplicación WinRT

Alrededor de una cuarta parte de las veces, si paso por el código, realmente regresará y leerá el archivo.

Aquí es una versión muy simplificada del código:

App.xaml.cs:

protected override void OnLaunched(LaunchActivatedEventArgs args) 
{ 
    FileLoader.Load().Wait(); 

    // File-load dependent stuff 
} 

FileLoader.cs:

public async static Task Load() 
{ 
    StorageFolder folder = ApplicationData.Current.LocalFolder; 
    StorageFile file; 
    bool fileExists = true; 

    try 
    { 
     // The following line (often) never returns 
     file = await folder.GetFileAsync("filename.xml"); 
    { 
    catch 
    { 
     fileExists = false; 
    } 

    // Do stuff with loaded file 
} 

Si miro la ventana Resultados de Visual Studio , después de un rato de esperar obtengo "The thread '<No Name>' (0x30c) has exited with code 0 (0x0)."

¿Alguien tiene alguna idea de ¿que esta pasando aqui?

+6

Está bloqueando el subproceso de interfaz de usuario por lo que puedo ver al llamar 'Espera'. Esa es una muy mala idea. Diablos, eso podría ser incluso lo que está causando el problema. –

+1

Creo que Jon tiene razón: ¿hay alguna posibilidad de que marques OnLaunched como asincrónico y esperes la llamada Load()? Si no puede, entonces otro enfoque podría ser que Load ejecute una acción después de que la carga haya terminado y luego ejecute la acción al final (o, por supuesto, puede usar ContinueWith en la tarea que Load() devuelve al igual que antes asincrónica/espera :) –

+0

Ambos tenían razón, Jon y James. ¡Muchas gracias por la entrada! Originalmente estaba usando 'Wait' porque no me di cuenta de que podías agregar' async' a un método reemplazado, y no sabía que 'OnLaunched' se estaba ejecutando en el hilo de UI. Quitar 'Wait' y agregar' async' a 'OnLaunched' lo solucionó. Me gustaría poder marcar sus comentarios como la respuesta. – jokeefe

Respuesta

47

De forma predeterminada, cuando await a que aún no se ha completado, el método se reanuda en un contexto capturado (en este caso, el contexto de la interfaz de usuario).

lo tanto, aquí es la razón por su código está fallando:

  • OnLaunched llamadas Load (dentro del contexto de la interfaz de usuario).
  • Load espera. Esto hace que el método Load devuelva una tarea incompleta y programe su finalización para más adelante. Esta continuación está programada para el contexto de la interfaz de usuario.
  • OnLaunched bloques en la tarea devuelta desde Load. Esto bloquea el hilo de UI.
  • GetFileAsync finaliza e intenta ejecutar la continuación para Load.
  • La continuación de Load espera a que el subproceso de interfaz de usuario esté disponible para que pueda ejecutarse en el contexto de la interfaz de usuario.
  • En este punto, OnLaunched está esperando que se complete Load (bloqueando el hilo de la interfaz de usuario al hacerlo), y Load está esperando que el subproceso de la interfaz de usuario esté libre. Punto muerto.

Estas mejores prácticas evitar esta situación:

  1. En su "biblioteca" async métodos, utilizar ConfigureAwait(false) siempre que sea posible. En su caso, esto cambiaría await folder.GetFileAsync("filename.xml"); a await folder.GetFileAsync("filename.xml").ConfigureAwait(false);.
  2. No bloquear en Task s; es async todo el camino hacia abajo. En otras palabras, reemplace Wait con await.

Para más información:

actualización, 2012-07-13: incorporado esta respuesta into a blog post.

+0

¡Excelente respuesta! Muchas gracias por la explicación detallada de lo que está sucediendo y la extensa lista de artículos de referencia. Esto hace todo mucho más claro. – jokeefe

+0

Esto fue perfecto. Esto me ahorró tanto dolor que fue increíble. – ohmusama

+1

Deseo que MS esté muerto. Definitivamente buscan a personas que les proporcionen cosas tan locas. ¿Por qué diablos no dejaron los hilos de la vieja moda y las primitivas de sincronización? Morones. –

Cuestiones relacionadas