Event-based Asynchronous Pattern Overview

Aplicativos que realizar várias tarefas simultaneamente, embora permaneçam responsivo a interação do usuário, geralmente exigem um design que usa vários threads. O System.Threading namespace fornece todas as ferramentas necessárias para criar aplicativos multithread de alto desempenho, mas efetivamente o uso dessas ferramentas requer experiência significativa com a engenharia de software multithread. Em aplicativos multithreaded relativamente simples, o BackgroundWorker componente fornece uma solução simples. Para aplicativos mais sofisticados de assíncronos, considere a implementação de uma classe que segue o padrão assíncrono baseado em eventos.

O padrão assíncrono baseado em evento disponibiliza as vantagens de aplicativos de vários segmentos enquanto oculta muitas das questões complexas inerentes ao design de vários segmentos. Usando uma classe que ofereça suporte a esse padrão pode permitir que você:

  • Executar tarefas demoradas, como, por exemplo, downloads e as operações de banco de dados, "em segundo plano" sem interromper o seu aplicativo.

  • Execute várias operações simultaneamente, recebendo notificações quando a cada conclusão.

  • Aguardar recursos se tornarem disponíveis, sem parar ("deslocado") do aplicativo.

  • Se comunicam usando o conhecido modelo de eventos e delegados de operações assíncronas pendentes. Para obter mais informações sobre o uso de manipuladores de eventos e delegados, consulte Eventos e representantes.

Uma classe que suporte o padrão assíncrono baseado em evento terá um ou mais métodos chamados MethodNameAsync. Esses métodos podem espelhar versões síncronas, o qual executam a mesma operação no segmento atual. A classe também pode ter um MethodNameCompleted evento e ele podem ter um MethodNameAsyncCancel (ou simplesmente CancelAsync) método.

PictureBoxé um componente típico que suporta o padrão assíncrono baseado em eventos. Você pode baixar uma imagem de forma síncrona chamando seu Load método, mas se a imagem for grande, ou se a conexão de rede estiver lenta, seu aplicativo irá parar ("travar") até que a operação de download é concluída e a chamada para Load retorna.

Se desejar que o seu aplicativo seja executado enquanto a imagem está carregando, você pode chamar o LoadAsync método e o identificador do LoadCompleted evento, assim como você trataria de qualquer outro evento. Quando você chama o LoadAsync método, o aplicativo irá continuar a ser executado enquanto o download continua em um thread separado ("no plano de fundo"). O manipulador de eventos será chamado quando a operação de carregamento da imagem é concluída e o manipulador de eventos pode examinar o AsyncCompletedEventArgs parâmetro para determinar se o download foi concluído com êxito.

O padrão assíncrono baseado em evento requer que uma operação assíncrona pode ser cancelada e o PictureBox controle oferece suporte a esse requisito com sua CancelAsync método. Chamando CancelAsync envia uma solicitação para parar o download pendente, e quando a tarefa for cancelada, o LoadCompleted evento é gerado.

Observação de cuidadoCuidado

É possível que o download terminará assim como o CancelAsync solicitação é feita, isso Cancelled pode não refletir a solicitação para cancelar.Isso é chamado de um condição de corrida e é um problema comum de programação multithread.Para obter mais informações sobre problemas de programação multithread, consulte Práticas recomendadas de threads gerenciadas.

Características do padrão assíncrono baseado em evento

O padrão assíncrono baseado em eventos pode levar várias formas, dependendo da complexidade das operações suportadas por uma determinada classe. As classes mais simples podem ter um único método MethodNameAsync e um evento correspondente MethodNameCompleted. Classes mais complexas podem ter vários métodos MethodNameAsync, cada um com um evento correspondente MethodNameCompleted, bem como versões síncronas desses métodos. Classes podem opcionalmente suportar cancelamento, relatórios de progresso, e resultados incrementais para cada método assíncrono.

Um método assíncrono também pode oferecer suporte a várias chamadas pendentes (várias chamadas simultâneas), permitindo a seu código chamá-las qualquer número de vezes antes que ele conclua outras operações pendentes. Corretamente tratamento essa situação pode exigir de seu aplicativo controlar a conclusão de cada operação.

Exemplos do padrão assíncrono baseado em evento

O SoundPlayer e PictureBox componentes representam implementações simples do Event-based Asynchronous padrão. O WebClient e BackgroundWorker componentes representam as implementações mais complexas do Event-based Asynchronous padrão.

A seguir é uma declaração de classe de exemplo está de acordo com o padrão:

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.
}

O fictícia AsyncExample classe tem dois métodos, que dão suporte para chamadas síncronas e assíncronas. Sobrecargas de síncronas se comportam como qualquer chamada de método e executar a operação no thread de chamada; Se a operação é demorada, pode haver um atraso considerável antes da chamada retorna. Sobrecargas de assíncronas irá iniciar a operação em outro thread e retornar imediatamente, permitindo que o thread de chamada continuar enquanto a operação está sendo executado "em"segundo plano.

Sobrecargas de método assíncrono

Há potencialmente duas sobrecargas para operações assíncronas: invocação de único e múltiplo invocação. Você pode distinguir dessas duas formas por suas assinaturas de método: o formulário de invocação de vários tem um parâmetro extra chamado userState. Este formulário possibilita que seu código para chamar Method1Async(string param, object userState) várias vezes sem esperar que as operações assíncronas pendentes para concluir. Se, por outro lado, você tenta chamar Method1Async(string param) antes de uma chamada anterior tiver sido concluído, o método gera um InvalidOperationException.

O userState parâmetro para as sobrecargas de invocação de múltiplos permite distinguir entre as operações assíncronas. Você fornecer um valor exclusivo (por exemplo, um código hash ou de GUID) para cada chamada para Method1Async(string param, object userState), e quando cada operação é concluída, o seu manipulador de eventos pode determinar qual instância da operação gerado o evento de conclusão.

Rastreamento de operações pendentes

Se você usar sobrecargas de invocação de múltiplos, seu código será necessário controlar o userState objetos (IDs de tarefa) para pendente de tarefas. Para cada chamada para Method1Async(string param, object userState), você normalmente irá gerar um novo exclusivo userState de objeto e adicioná-la à coleção. Quando a tarefa correspondente a esta userState objeto gera o evento de conclusão, examinará a implementação do método de conclusão AsyncCompletedEventArgs.UserState e removê-lo da coleção. Usado dessa forma, o userState parâmetro usa a função de uma tarefa de identificação.

Observação

Você deve ter cuidado para fornecer um valor exclusivo para userState em suas chamadas a invocação de várias sobrecargas.Identificações de tarefas não-exclusivo fará com que a classe assíncrona throw um ArgumentException.

Cancelando operações pendentes

É importante ser capaz de cancelar operações assíncronas a qualquer momento antes de sua conclusão. Classes que implementam o padrão assíncrono baseado em evento terá uma CancelAsync método (se houver apenas um método assíncrono) ou um MethodNameAsyncCancel método (se existirem vários métodos assíncronos).

Métodos que permitem que várias chamadas levar uma userState parâmetro, que pode ser usado para controlar o tempo de vida de cada tarefa. CancelAsyncleva um userState parâmetro, que permite que você cancelar determinado pendentes tarefas.

Os métodos que oferecem suporte a apenas uma única operação de cada vez, pendente como Method1Async(string param), não é cancelável.

Recebendo atualizações de andamento e resultados incrementais

Uma classe que segue o padrão assíncrono baseado em evento opcionalmente pode fornecer um evento para rastrear o progresso e resultados incrementais. Isso geralmente será denominado ProgressChanged ou MethodNameProgressChanged, e seu manipulador de eventos correspondente levará um ProgressChangedEventArgs parâmetro.

O manipulador de eventos para o ProgressChangedevento pode examinar o ProgressChangedEventArgs.ProgressPercentage propriedade para determinar qual porcentagem de uma tarefa assíncrona foi concluída. Essa propriedade irá variar de 0 a 100 e pode ser usado para atualizar o Value propriedade de um ProgressBar. Se várias operações assíncronas pendentes, você pode usar o ProgressChangedEventArgs.UserState propriedade para distinguir qual operação está relatando progresso.

Algumas classes podem relatar resultados incrementais como proceder de operações assíncronas. Esses resultados serão armazenados em uma classe que deriva de ProgressChangedEventArgs e eles aparecerão como propriedades em que a classe de derivada. Você pode acessar esses resultados no manipulador de eventos para o ProgressChanged evento, exatamente como você acessaria o ProgressPercentage propriedade. Se várias operações assíncronas pendentes, você pode usar o UserState propriedade para distinguir qual operação está relatando resultados incrementais.

Consulte também

Tarefas

Como: Usar componentes que suportam o padrão assíncrono baseado em evento

Como: Executar uma operação em segundo plano

Como: Implementar um formulário que usa uma operação de plano de fundo

Referência

ProgressChangedEventArgs

BackgroundWorker

AsyncCompletedEventArgs

Conceitos

Práticas recomendadas para implementar o padrão assíncrono baseado em evento

Decidir quando implementar o padrão assíncrono baseado em evento

Outros recursos

Programação multithread com o padrão assíncrono baseado em evento