understanding - ¿Qué significa exactamente ''contexto'' en el código C#async/await?
task run async c# (2)
Como describo en mi entrada de blog de introducción async
, el "contexto" es:
-
SynchronizationContext.Current
, a menos que seanull
, en cuyo caso es -
TaskScheduler.Current
. Tenga en cuenta que si no hay un programador de tareas actual,TaskScheduler.Current
es el mismo queTaskScheduler.Default
, que es un contexto de grupo de subprocesos.
La gran mayoría de las veces, esto es un contexto de solicitud UI o ASP.NET (ambos tipos de SynchronizationContext
), o bien es el contexto del grupo de subprocesos. Los contextos del programador de tareas rara vez entran en juego.
Tenga en cuenta que este contexto solo se utiliza para programar la continuación . No hace nada con el cálculo de referencias; en su ejemplo, obj
se captura tal como sería si se hiciera referencia a una expresión lambda.
Veamos algunos códigos simples de C # async / await donde tengo una referencia de objeto ( obj
) antes y después de una await
con ConfigureAwait(false)
private async Task<SomeObject> AnAsyncLibraryMethod(SomeObject obj)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
obj.Name = "Harry"; // <-- obj here
// MAIN POINT
var newSubObj = await FetchOverHttpAsync().ConfigureAwait(false);
// Continuation here
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
obj.Name = "Sally"; // <-- same obj here
return obj;
}
public class SomeObject { public string Name; }
ConfigureAwait(false)
parece no indicar la continuación del contexto original capturado , pero ¿qué significa eso realmente? He intentado el código anterior y obj
se referencia correctamente en la parte posterior (incluso cuando se reanuda en un subproceso diferente).
Por lo tanto, el "contexto" no parece ser la memoria de trabajo del hilo (es decir, el almacenamiento local del hilo). Entonces, ¿qué contiene "contexto"? Por lo tanto, ¿qué significa realmente para
marque la continuación de vuelta al contexto original capturado
Si no estoy totalmente equivocado, ConfigureAwait(false);
solo significa que el código que se ejecuta después del código que está esperando, no está obligado a usar SynchronizationContext
desde antes de la espera.
SynchronizationContext
puede ser diferente según lo señalado por Stephen. Entonces, imagine que está en un entorno web y su código después de la espera depende de HttpContext.Current.Items, esto podría no funcionar más si configura ConfigureAwait(false);
El siguiente código en un controlador MVC lanzaría una excepción por ejemplo
public async Task<ActionResult> Index()
{
System.Web.HttpContext.Current.Items["test"] = "test";
var result = await SomethingAsync();
return View();
}
private async Task<object> SomethingAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
// this will throw a nullpointer if ConfigureAwait is set to false
return System.Web.HttpContext.Current.Items["test"];
}
Sin embargo, su variable está simplemente en el alcance del método y, por lo tanto, estará disponible, básicamente el método de cierre / alcance, si esto tiene sentido.