Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Las aplicaciones que realizan muchas tareas simultáneamente, pero siguen respondiendo a la interacción del usuario, a menudo requieren un diseño que use varios subprocesos. El System.Threading espacio de nombres proporciona todas las herramientas necesarias para crear aplicaciones multiproceso de alto rendimiento, pero el uso de estas herramientas requiere eficazmente una experiencia significativa con la ingeniería de software multiproceso. En el caso de las aplicaciones multiproceso relativamente sencillas, el BackgroundWorker componente proporciona una solución sencilla. Para aplicaciones asincrónicas más sofisticadas, considere la posibilidad de implementar una clase que cumpla el patrón asincrónico basado en eventos.
El patrón asincrónico basado en eventos pone a disposición las ventajas de las aplicaciones multiproceso mientras oculta muchos de los problemas complejos inherentes al diseño multiproceso. El uso de una clase que admita este patrón puede permitirle:
Realice tareas que consumen mucho tiempo, como descargas y operaciones de base de datos, "en segundo plano", sin interrumpir la aplicación.
Ejecute varias operaciones simultáneamente y reciba notificaciones cuando se complete cada una.
Espere a que los recursos estén disponibles sin detener ("bloquear") la aplicación.
Comunicarse con operaciones asincrónicas pendientes mediante el modelo conocido de eventos y delegados. Para obtener más información sobre el uso de controladores de eventos y delegados, vea Eventos.
Una clase que admita el patrón asincrónico basado en eventos tendrá uno o varios métodos denominados MethodNameAsync. Estos métodos pueden reflejar versiones sincrónicas, que realizan la misma operación en el subproceso actual. La clase también puede tener un evento MethodNameCompleted y puede tener un método MethodNameAsyncCancel (o simplemente CancelAsync).
PictureBox es un componente típico que admite el patrón asincrónico basado en eventos. Puede descargar una imagen de forma sincrónica llamando a su Load método, pero si la imagen es grande o si la conexión de red es lenta, la aplicación dejará de responder hasta que se complete la operación de descarga y la llamada a Load devuelva.
Si quiere que la aplicación siga ejecutándose mientras se carga la imagen, puede llamar al LoadAsync método y controlar el LoadCompleted evento, igual que controlaría cualquier otro evento. Al llamar al LoadAsync método , la aplicación seguirá ejecutándose mientras la descarga continúa en un subproceso independiente ("en segundo plano"). Se llamará al controlador de eventos cuando se complete la operación de carga de imágenes y el controlador de eventos puede examinar el AsyncCompletedEventArgs parámetro para determinar si la descarga se completó correctamente.
El patrón asincrónico basado en eventos requiere que se pueda cancelar una operación asincrónica y el PictureBox control admite este requisito con su CancelAsync método. Al llamar CancelAsync, se envía una solicitud para detener la descarga pendiente, y cuando se cancela la tarea, se genera el evento LoadCompleted.
Precaución
Es posible que la descarga finalice igual que se realiza la CancelAsync solicitud, por lo que Cancelled es posible que no refleje la solicitud para cancelar. Esto se denomina condición de carrera y es un problema común en la programación multiproceso. Para obtener más información sobre los problemas de programación multiproceso, consulte Procedimientos recomendados de subprocesos administrados.
Características del patrón asincrónico basado en eventos
El patrón asincrónico basado en eventos puede tener varias formas, en función de la complejidad de las operaciones admitidas por una clase determinada. Las clases más sencillas pueden tener un único método MethodNameAsync y un evento MethodNameCompleted correspondiente. Las clases más complejas pueden tener varios métodos MethodNameAsync, cada uno con un evento MethodNameCompleted correspondiente, así como versiones sincrónicas de estos métodos. Las clases pueden admitir opcionalmente la cancelación, los informes de progreso y los resultados incrementales para cada método asincrónico.
Un método asincrónico también puede admitir varias llamadas pendientes (varias invocaciones simultáneas), lo que permite al código llamarlo cualquier número de veces antes de completar otras operaciones pendientes. El control correcto de esta situación puede requerir que la aplicación realice un seguimiento de la finalización de cada operación.
Ejemplos del patrón asincrónico basado en eventos
Los SoundPlayer componentes y PictureBox representan implementaciones simples del patrón asincrónico basado en eventos. Los WebClient componentes y BackgroundWorker representan implementaciones más complejas del patrón asincrónico basado en eventos.
A continuación se muestra una declaración de clase de ejemplo que se ajusta al patrón:
Public Class AsyncExample
' Synchronous methods.
Public Function Method1(ByVal param As String) As Integer
Public Sub Method2(ByVal param As Double)
' Asynchronous methods.
Overloads Public Sub Method1Async(ByVal param As String)
Overloads Public Sub Method1Async(ByVal param As String, ByVal userState As Object)
Public Event Method1Completed As Method1CompletedEventHandler
Overloads Public Sub Method2Async(ByVal param As Double)
Overloads Public Sub Method2Async(ByVal param As Double, ByVal userState As Object)
Public Event Method2Completed As Method2CompletedEventHandler
Public Sub CancelAsync(ByVal userState As Object)
Public ReadOnly Property IsBusy () As Boolean
' Class implementation not shown.
End Class
public class AsyncExample
{
// Synchronous methods.
public int Method1(string param);
public void Method2(double param);
// Asynchronous methods.
public void Method1Async(string param);
public void Method1Async(string param, object userState);
public event Method1CompletedEventHandler Method1Completed;
public void Method2Async(double param);
public void Method2Async(double param, object userState);
public event Method2CompletedEventHandler Method2Completed;
public void CancelAsync(object userState);
public bool IsBusy { get; }
// Class implementation not shown.
}
La clase ficticia AsyncExample
tiene dos métodos, ambos que admiten invocaciones sincrónicas y asincrónicas. Las sobrecargas sincrónicas se comportan como cualquier llamada de método y ejecutan la operación en el subproceso que realiza la llamada; Si la operación consume mucho tiempo, puede haber un retraso notable antes de que se devuelva la llamada. Las sobrecargas asincrónicas iniciarán la operación en otro subproceso y, a continuación, devolverán inmediatamente, lo que permite que el subproceso que realiza la llamada continúe mientras la operación se ejecuta "en segundo plano".
Sobrecargas de método asincrónico
Hay potencialmente dos sobrecargas para las operaciones asincrónicas: invocación única e invocación múltiple. Puede distinguir estos dos formularios por sus firmas de método: el formulario de invocación múltiple tiene un parámetro adicional denominado userState
. Este formulario permite que el código llame Method1Async(string param, object userState)
varias veces sin esperar a que finalicen las operaciones asincrónicas pendientes. Si, por el contrario, intenta llamar a Method1Async(string param)
antes de que se haya completado una invocación anterior, el método genera un InvalidOperationException.
El userState
parámetro de las sobrecargas de invocación múltiple permite distinguir entre operaciones asincrónicas. Se proporciona un valor único (por ejemplo, un GUID o código hash) para cada llamada a Method1Async(string param, object userState)
y, cuando se completa cada operación, el controlador de eventos puede determinar qué instancia de la operación generó el evento de finalización.
Seguimiento de operaciones pendientes
Si usa sobrecargas de invocación múltiple, el código necesitará realizar un seguimiento de los objetos userState
(id. de tareas) de las tareas pendientes. Para cada llamada a Method1Async(string param, object userState)
, normalmente generará un nuevo objeto único userState
y lo agregará a una colección. Cuando la tarea correspondiente a este userState
objeto genera el evento de finalización, la implementación del método de finalización examinará AsyncCompletedEventArgs.UserState y la quitará de la colección. Se usa de esta manera, el userState
parámetro toma el rol de un identificador de tarea.
Nota:
Asegúrese de proporcionar un valor único para userState
en las llamadas a sobrecargas de invocación múltiple. Los id. de tarea que no sean únicos provocarán que la clase asincrónica genere una ArgumentException.
Cancelación de operaciones pendientes
Es importante poder cancelar las operaciones asincrónicas en cualquier momento antes de su finalización. Las clases que implementan el patrón asincrónico basado en eventos tendrán un CancelAsync
método (si solo hay un método asincrónico) o un método MethodNameAsyncCancel (si hay varios métodos asincrónicos).
Los métodos que permiten varias invocaciones toman un userState
parámetro, que se puede usar para realizar un seguimiento de la duración de cada tarea.
CancelAsync
toma un userState
parámetro , que permite cancelar tareas pendientes concretas.
Los métodos que admiten solo una operación pendiente a la vez, como Method1Async(string param)
, no se pueden cancelar.
Recepción de actualizaciones de progreso y resultados incrementales
Una clase que se adhiere al patrón asincrónico basado en eventos puede proporcionar opcionalmente un evento para realizar un seguimiento del progreso y los resultados incrementales. Normalmente se denominará ProgressChanged
o MethodNameProgressChanged y su controlador de eventos correspondiente tomará un ProgressChangedEventArgs parámetro.
El controlador de eventos del ProgressChanged
evento puede examinar la ProgressChangedEventArgs.ProgressPercentage propiedad para determinar qué porcentaje de una tarea asincrónica se ha completado. Esta propiedad oscilará entre 0 y 100 y se puede usar para actualizar la Value propiedad de un ProgressBar. Si hay varias operaciones asincrónicas pendientes, puede usar la propiedad ProgressChangedEventArgs.UserState para distinguir qué operación está notificando el progreso.
Algunas clases pueden notificar resultados incrementales a medida que continúan las operaciones asincrónicas. Estos resultados se almacenarán en una clase que derive de ProgressChangedEventArgs y aparecerán como propiedades en la clase derivada. Puede acceder a estos resultados en el controlador de eventos para el ProgressChanged
evento, igual que accedería a la ProgressPercentage propiedad . Si hay varias operaciones asincrónicas pendientes, puede usar la propiedad UserState para distinguir qué operación informa de resultados incrementales.
Consulte también
- ProgressChangedEventArgs
- BackgroundWorker
- AsyncCompletedEventArgs
- Cómo: Usar componentes que admiten el patrón asincrónico basado en eventos
- Cómo: Ejecutar una operación en segundo plano
- Cómo: Implementar un formulario que usa una operación en segundo plano
- Modelo asincrónico basado en eventos (EAP)
- Procedimientos recomendados para implementar el patrón asincrónico basado en eventos
- Decidir cuándo implementar el patrón asincrónico basado en eventos