Desarrollador .NET: pregunta de entrevista
¿Cómo puede async/await causar deadlocks en .NET?
Puede haber deadlock cuando código bloquea con Task.Result o Wait y la continuación necesita el contexto capturado. Mantén toda la cadena async, usa await, evita sync-over-async y no mantengas locks durante await.
Respuesta directa
Qué debe cubrir una buena respuesta
Cómo funciona
En entornos con contexto de sincronización, como ASP.NET clásico, WPF o WinForms, un await captura el contexto y programa su continuación de vuelta en él. Si el código llamador bloquea ese mismo contexto con .Result o .Wait, la continuación nunca puede ejecutarse y ambos lados esperan para siempre. ASP.NET Core no tiene contexto de sincronización, así que el deadlock clásico desaparece, pero el sync-over-async sigue quemando hilos del pool y provoca inanición bajo carga. El remedio es async de principio a fin: await en todo, ConfigureAwait(false) en código de biblioteca y nunca sostener un lock a través de un await.
Ejemplo
Un handler de botón WPF llamaba a LoadAsync().Result; LoadAsync esperaba una llamada HTTP cuya continuación necesitaba el hilo de UI bloqueado en Result, congelando la aplicación. Cambiar el handler a async void con await, y la biblioteca a ConfigureAwait(false), eliminó el bloqueo. En una API ASP.NET Core el mismo .Result no bloqueó pero agotó el pool de hilos con 200 solicitudes concurrentes.
Errores frecuentes
- Llamar a .Result o .GetAwaiter().GetResult() desde código que corre en un contexto capturado.
- Usar lock alrededor de un await, que no compila, y pasar a un Monitor que luego abarca el await.
- Suponer que ASP.NET Core hace inofensivo bloquear sobre tareas.
Una estructura útil para responder
Responde desde tu propia experiencia.
No memorices un guion: usa solo ejemplos que puedas explicar con honestidad en preguntas posteriores.
Abre el espacio de trabajo de escritorio y ensaya una respuesta clara con tus propias palabras.