Actualización: ASP.NET Core no tiene unSynchronizationContext . Si está en ASP.NET Core, no importa si lo usa ConfigureAwait(false)o no.
Para ASP.NET "Completo" o "Clásico" o lo que sea, el resto de esta respuesta aún se aplica.
Publicación original (para ASP.NET no Core):
Este video del equipo de ASP.NET tiene la mejor información sobre el uso asyncen ASP.NET.
Había leído que es más eficiente ya que no tiene que cambiar los contextos de hilo al contexto de hilo original.
Esto es cierto con las aplicaciones de interfaz de usuario, donde solo hay un hilo de interfaz de usuario al que debe "sincronizar" nuevamente.
En ASP.NET, la situación es un poco más compleja. Cuando un asyncmétodo reanuda la ejecución, toma un hilo del grupo de hilos ASP.NET. Si deshabilita el uso de la captura de contexto ConfigureAwait(false), entonces el hilo simplemente continúa ejecutando el método directamente. Si no deshabilita la captura de contexto, el hilo volverá a ingresar el contexto de solicitud y luego continuará ejecutando el método.
Por ConfigureAwait(false)lo tanto, no le ahorra un salto de hilo en ASP.NET; le ahorra el reingreso del contexto de solicitud, pero esto normalmente es muy rápido. ConfigureAwait(false) podría ser útil si está intentando hacer una pequeña cantidad de procesamiento paralelo de una solicitud, pero realmente TPL es una mejor opción para la mayoría de esos escenarios.
Sin embargo, con ASP.NET Web Api, si su solicitud llega en un hilo, y espera alguna función y llama a ConfigureAwait (falso) que podría ponerlo en un hilo diferente cuando devuelva el resultado final de su función ApiController .
En realidad, solo hacer un awaitpuede hacer eso. Una vez que su asyncmétodo llega a un await, el método se bloquea pero el subproceso vuelve al grupo de subprocesos. Cuando el método está listo para continuar, cualquier subproceso se extrae del grupo de subprocesos y se utiliza para reanudar el método.
La única diferencia que ConfigureAwaithace en ASP.NET es si ese hilo ingresa al contexto de solicitud al reanudar el método.
Tengo más información de fondo en mi artículo de MSDNSynchronizationContext y en mi asyncentrada de blog de introducción .
HttpContext.Currentes operado por ASP.NETSynchronizationContext, que fluye de manera predeterminada cuando ustedawait, pero no lo haceContinueWith. OTOH, el contexto de ejecución (incluidas las restricciones de seguridad) es el contexto mencionado en CLR a través de C #, y es fluido por ambosContinueWithyawait(incluso si lo usaConfigureAwait(false)).ConfigureAwaitrealidad solo tiene sentido cuando espera tareas , mientras queawaitactúa en cualquier "espera". Otras opciones consideradas fueron: ¿Debería el comportamiento predeterminado descartar el contexto si se encuentra en una biblioteca? ¿O tiene una configuración de compilador para el comportamiento de contexto predeterminado? Ambos fueron rechazados porque es más difícil simplemente leer el código y decir lo que hace.ConfigureAwait(false)evitar un punto muerto basado enResult/Waitporque en ASP.NET no debería usarResult/Waiten primer lugar.Breve respuesta a su pregunta: No. No debe llamar
ConfigureAwait(false)al nivel de aplicación de esa manera.TL; Versión DR de la respuesta larga: si está escribiendo una biblioteca donde no conoce a su consumidor y no necesita un contexto de sincronización (que no debería en una biblioteca, creo), siempre debe usar
ConfigureAwait(false). De lo contrario, los consumidores de su biblioteca pueden enfrentar puntos muertos al consumir sus métodos asincrónicos de manera bloqueante. Esto depende de la situación.Aquí hay una explicación un poco más detallada sobre la importancia del
ConfigureAwaitmétodo (una cita de mi publicación de blog):Además, aquí hay dos excelentes artículos para usted que son exactamente para su pregunta:
Finalmente, hay un gran video corto de Lucian Wischik exactamente sobre este tema: los métodos de la biblioteca asíncrona deberían considerar el uso de Task.ConfigureAwait (falso) .
Espero que esto ayude.
fuente
Taskcamina por la pila para obtener elSynchronizationContext, que está mal. SeSynchronizationContexttoma antes de la llamada alTasky luego se continúa con el resto del códigoSynchronizationContextsiSynchronizationContext.Currentno es nulo.SynchronizationContext.Currentesté claro / o que la biblioteca se llame dentro de un enTask.Run()lugar de tener que escribir en.ConfigureAwait(false)toda la biblioteca de la clase?.ConfigureAwait(false)s. Quizás sería más fácil para los autores de bibliotecas si ese fuera el comportamiento predeterminado, pero supongo que hacer un poco más difícil escribir una biblioteca correctamente es mejor que hacer un poco más difícil escribir una aplicación correctamente.El mayor inconveniente que he encontrado al usar ConfigureAwait (falso) es que la cultura del hilo se revierte a los valores predeterminados del sistema. Si ha configurado una cultura, por ejemplo ...
y está alojando en un servidor cuya cultura está configurada en en-EE. UU., Entonces encontrará antes de que ConfigureAwait (falso) se llame CultureInfo. es decir
Si su aplicación está haciendo algo que requiere un formato de datos específico de la cultura, deberá tener esto en cuenta al usar ConfigureAwait (falso).
fuente
ConfigureAwait(false)se usa.Tengo algunas ideas generales sobre la implementación de
Task:using.ConfigureAwaitse introdujo en 4.5.Taskfue introducido en 4.0.Task.ContinueWithb / c no se dio cuenta de que el cambio de contexto es costoso y está desactivado de forma predeterminada.Tengo algunas publicaciones sobre el tema, pero mi opinión, además de la buena respuesta de Tugberk, es que debes convertir todas las API en asíncronas e idealmente fluir el contexto. Como está haciendo asíncrono, simplemente puede usar continuaciones en lugar de esperar para que no se produzca un punto muerto, ya que no se realiza ninguna espera en la biblioteca y se mantiene el flujo para que se conserve el contexto (como HttpContext).
El problema es cuando una biblioteca expone una API síncrona pero usa otra API asíncrona; por lo tanto, debe usar
Wait()/Resulten su código.fuente
Task.Disposesi quieres; simplemente no necesitas la gran mayoría de las veces. 2)Taskse introdujo en .NET 4.0 como parte de la TPL, que no necesitabaConfigureAwait; cuandoasyncse agregó, reutilizaron elTasktipo existente en lugar de inventar uno nuevoFuture.Tasks; el "contexto" controlado porContinueWithes unSynchronizationContextoTaskScheduler. Estos diferentes contextos se explican en detalle en el blog de Stephen Toub .Threads, pero ya no lo hace conContinueWith()), esto hace que su respuesta sea confusa de leer.