c# - runsql - update inner join access
Actualizaciones de Task.Run y UI Progress (3)
El constructor Progress<T>
captura el objeto SynchronizationContext
actual.
La clase SynchronizationContext
es una instalación que resume los detalles del modelo de subprocesos involucrado. Es decir, en Windows Forms utilizará Control.Invoke
, en WPF utilizará Dispatcher.Invoke
, etc.
Cuando se llama al objeto Progress
, el propio objeto Progress
sabe que debe ejecutar su delegado utilizando el SynchronizationContext
capturado.
En otros términos, funciona porque Progress
ha sido diseñado para manejar eso sin que el desarrollador tenga que decirlo explícitamente.
Este fragmento de código es del blog de Stephen Cleary y proporciona un ejemplo de cómo informar el progreso cuando se utiliza Task.Run. Me gustaría saber por qué no hay problemas de subprocesos cruzados con la actualización de la interfaz de usuario, por lo que quiero decir, ¿por qué no es necesario invocar?
private async void button2_Click(object sender, EventArgs e)
{
var progressHandler = new Progress<string>(value =>
{
label2.Text = value;
});
var progress = progressHandler as IProgress<string>;
await Task.Run(() =>
{
for (int i = 0; i != 100; ++i)
{
if (progress != null)
progress.Report("Stage " + i);
Thread.Sleep(100);
}
});
label2.Text = "Completed.";
}
Parece que estás confundido debido al hecho de que parte de esta maquinaria de hilos cruzados está oculta a los ojos del desarrollador, así que solo tienes que "tomar y usar": http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx
Presentamos la interfaz de IProgress para permitirle crear una experiencia para mostrar el progreso. Esta interfaz expone un método de Informe (T), que la tarea asíncrona llama para informar el progreso. Expone esta interfaz en la firma del método asíncrono, y la persona que llama debe proporcionar un objeto que implemente esta interfaz. Juntos, la tarea y la persona que llama crean un enlace muy útil (y podrían ejecutarse en diferentes subprocesos).
También proporcionamos la clase Progress, que es una implementación de IProgress. Se recomienda utilizar Progreso en su implementación, ya que maneja toda la contabilidad relacionada con el guardado y la restauración del contexto de sincronización. El progreso expone tanto un evento como una devolución de llamada de acción, que se invoca cuando la tarea informa el progreso. Este patrón le permite escribir código que simplemente reacciona a los cambios de progreso a medida que ocurren. Juntos, IProgress y Progress proporcionan una forma fácil de pasar información de progreso de una tarea en segundo plano al subproceso de la interfaz de usuario.
Solo una cosa más que mencionar: la notificación de progreso se invocará una vez que se haya completado la parte del trabajo, no solo en ese momento . Por lo tanto, si el subproceso de la interfaz de usuario está inactivo y tiene un núcleo de CPU de reserva, el retraso será casi cero. Si el subproceso de la interfaz de usuario está ocupado, la notificación no se invocará hasta el momento en que vuelva a estar inactiva (independientemente de la cantidad de núcleos de CPU de repuesto que tenga su computadora).
Progress<T>
captura el SynchronisationContext
actual cuando se crea una instancia. Cuando llama a Report
, lo delega en secreto en el contexto capturado. En el ejemplo, el contexto capturado es la interfaz de usuario, lo que significa que no se producen excepciones.