quinta-feira, 29 de maio de 2008

Executando métodos de forma assíncrona [Parte1 - Delegates]


Programação assíncrona é um assunto bastante completo e complexo. Um dos motivos para ser assim é que existem diversas formas para se executar código assincronamente, isto é, em uma thread separada. As principais estratégias são:
  • Usar a classe Thread;

  • Usar o componente BackgroundWorker;

  • Usar delegates;

Neste artigo vou falar da forma mais rápida de se executar um trecho de código em um thread separada e dedicada: através de delegates.

Existem três estratégias para executar código em uma thread dedicada, são eles:

  • Chame o método assíncronamente, faça alguma coisa e finalize a chamada assíncrona (a thread fica bloqueada até a o término da operação)

  • Chame o método assíncronamente, e enquanto a execução não terminar faça alguma coisa, e então finalize a chamada assíncrona.

  • Chame o método assínconamente, defina um CallBack para ser invocado no final da operação assíncorna, na implementação do CallBack finalize a chamada assíncrona.

A primeira coisa a se fazer é criar um delegate com a mesma assinatura do método que contém o código que se deseja executar assincronamente. Veja o exemplo:

Método:

public string BuscaDocumento(string autor, int posicao)

{

string caminho = string.Empty;

// faz alguma coisa

return caminho;

}

Delegate:

public delegate string BuscaDocumentoDelegate(string autor, int posicao);

Neste ponto já podemos realizar duas das estratégias de programação assíncrona usando delegates:

  • Chame o método assíncronamente, faça alguma coisa e finalize a chamada assíncrona (a thread fica bloqueada até a o término da operação)

  • Chame o método assíncronamente, e enquanto a execução não terminar faça alguma coisa, e então finalize a chamada assíncrona.

Vamos aos usos:

Caso 01: Chame o método assíncronamente, faça alguma coisa e finalize a chamada assíncrona (a thread fica bloqueada até a o término da operação)

BuscaDocumentoDelegate buscaDel = BuscaDocumento;

IAsyncResult result = buscaDel.BeginInvoke("Erico Veríssimo", 25, null, null);

//faça alguma coisa outra coisa

string resultado = buscaDel.EndInvoke(result); /* a thread bloqueia nesse ponto até que a operação BuscaDocumento seja concluida */

obs:

Os dois parâmetros nulos na chamada do método BeginInvoke são CallBack e State, respectivamente. Estes são necessários apenas para a terceira estratégia, a qual será demonstrada ainda neste artigo.

Caso 02: Chame o método assíncronamente, e enquanto a execução não terminar faça alguma coisa, e então finalize a chamada assíncrona.

BuscaDocumentoDelegate buscaDel = BuscaDocumento;

IAsyncResult result = buscaDel.BeginInvoke("Erico Veríssimo", 25, null, null);

while (!result.IsCompleted)

{

//faça qualquer coisa

}

string resultado = buscaDel.EndInvoke(result);

A vantagem desta implementação em relação às demais é que a thread principal não ficará bloqueada enquanto a thread em backgound não for concluída, o que permite que trechos de código sejam executados até a finalização da operação inciada via delegate.

A terceira forma é através de CallBacks, esta exige a implementação de outro método e será explicada a seguir.

Além do método com o código e do delegate equivalente é necessário um método de CallBack, que será invocado quando a operação assíncrona for concluída. O CallBack deve retornar void e receber um IasyncResult como argumento.

Método de CallBack:

public void BuscaDocumentoCallBack(IAsyncResult resultado)

{

BuscaDocumentoDelegate buscaDel = (BuscaDocumentoDelegate) resultado.AsyncState ;

string resultadoDaBusca = buscaDel.EndInvoke(resultado);

Console.WriteLine("Resultado da Busca: {0}", resultadoDaBusca);

}

Usando o delegate:


BuscaDocumentoDelegate buscaDel = BuscaDocumento;

buscaDel.BeginInvoke("Arnaldo Jabor", 34, BuscaDocumentoCallBack, buscaDel);

/* O fluxo desta thread continua, de modo que outras operações podem ser realizadas enquanto a operação em background prossegue, e quando esta finalizar o método BuscaDocumentoCallBack será invocado. */

Como podem ver não tem segredo. Essas técnicas são muito úteis em programas Windows Forms, pois nestes geralmente o usuário precisa de executar várias operações ao mesmo tempo, e além disso também são útis para processamentos longos que não necessitam de retorno imediato.

Em breve volto com Threads e BackgroundWorker!

Abraços,

Até

1 comentários:

Alexsandro_xpt disse...

Qual é a diferença de fazer assim e usar um objeto Thread?