valor - Comprender el contexto en C#5 asincrónico/aguardar
obtener variable de session c# (2)
¿Estoy en lo correcto al afirmar que async / await no tiene nada que ver con concurrencia / paralelismo y que no es más que una implementación de estilo de paso de continuación (CPS)? Y el enhebrado real se lleva a cabo por la instancia SynchronizationContext
que await
pases / restauraciones?
Si eso es correcto, tengo la siguiente pregunta sobre SynchronizationContext
:
garantiza que se ejecutará una continuación en el mismo hilo.
Sin embargo, ¿hay garantías de que la información de contexto del hilo persiste? Me refiero a Name
, CurrentPrincipal
, CurrentCulture
, CurrentUICulture
, etc. ¿Depende de framework (ASP.NET, WinForms, WCF, WPF)?
¿Estoy en lo cierto al decir que async / await no tiene nada que ver con la simultaneidad / paralelismo y no es más que la implementación de CPS?
Bueno, async
/ await
es una reescritura que usa CPS, por lo que su comprensión básica es correcta.
En cuanto a "concurrencia" y "paralelismo", diría que sí permite la concurrencia; puede iniciar varias operaciones async
que están todas "en vuelo" al mismo tiempo. Esto es fácil de hacer con Task.WhenAll
y Task.WhenAny
.
Además, aunque async
en sí mismo no implica "multihilo", Task.Run
habilita fácil async
multihilo compatible
Y el enhebrado real se lleva a cabo por la instancia SynchronizationContext que espera pases / restauraciones?
Piénselo de esta manera: la continuación creada por la reescritura de CPS tiene que ejecutarse en alguna parte . El "contexto asíncrono" capturado se puede utilizar para programar la continuación.
Nota al TaskScheduler.Current
: el contexto capturado es en realidad SynchronizationContext.Current
menos que sea nulo , en cuyo caso el contexto capturado es TaskScheduler.Current
.
Otra nota importante: la captura y restauración del contexto depende del objeto "awaiter". Por lo tanto, de forma predeterminada, si await
una Task
(o cualquier otro incorporado que se pueda esperar), el contexto será capturado y restaurado. Pero si await
el resultado de ConfigureAwait(false)
, entonces el contexto no se captura. Del mismo modo, si await
tu propia costumbre a la espera, no capturará el contexto (a menos que lo programes).
Sin embargo, ¿hay garantías de que la información de contexto del hilo persiste? Me refiero a Nombre, CurrentPrincipal, CurrentCulture, CurrentUICulture, etc.
SynchronizationContext
es diferente de ExecutionContext
. Una respuesta simplificada es que ExecutionContext
siempre "fluye", por lo que CurrentPrincipal
fluye (si no lo hizo, podría ser un problema de seguridad, por lo que las API que no fluyen ExecutionContext
siempre terminan en Unsafe
).
En las aplicaciones de interfaz de usuario, la cultura no fluye, pero de forma predeterminada es la misma para todos los hilos de todos modos. Name
definitivamente no va a fluir, a menos que reanude en el mismo hilo (por ejemplo, usando un UI SynchronizationContext
).
Para leer un poco más, recomiendo comenzar con mi propio tutorial async
/ await
y luego las preguntas frecuentes async
/ async
oficiales . Luego eche un vistazo a la publicación de blog de Stephen Toub en ExecutionContext
vs. SynchronizationContext
.
También puede encontrar mi artículo SynchronizationContext
útil.
No, las palabras clave async
/ await
tienen todo que ver con la concurrencia. async
/ await
básicamente envuelve su código de método en una tarea y continuación. Para ver la traducción exacta que produce el compilador (utilizando la Biblioteca de tareas paralelas) desensamble algunos fragmentos de código. Esta traducción del uso de async
/ await
es ''similar'' (¡pero no idéntica!) Al ejemplo a continuación
async Task<int> TaskOfTResult_MethodAsync()
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}
// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();
esto es aproximadamente convertido a
private int Result()
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}
donde espera la devolución fuera del método como
int? hours = null;
Task<int> task = null;
task = Task.Factory.StartNew<int>(() => Result());
task.ContnueWith(cont =>
{
// Some task completion checking...
hours = task.Result;
}, CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Current);
O bien, puede colocar el código TPL en el método de Result
private int ResultAsync()
{
int? hours = null;
Task<int> task = null;
task = Task.Factory.StartNew<int>(() =>
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}, CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Current);
try
{
return task.Result;
}
catch (AggregateException aggEx)
{
// Some handler method for the agg exception.
aggEx.Handle(HandleException);
}
}
SynchronizationContext
no garantiza que la continuación se ejecute en el mismo subproceso para el código async
/ awate
. Sin embargo, puede establecer el contexto utilizando el código TPL, a través de la palabra clave SynchronisationContex
.