Multi-threading do lado do cliente


Quando optamos por utilizar um proxy que fornece apenas a versão síncrona de uma operação, devemos ter cuidado quando efetuamos a chamada para a mesma através de múltiplas threads do lado do cliente.

Ao invocar uma operação do proxy, raramente invocamos o método Open do mesmo, que tem a finalidade de abrí-lo explicitamente, obrigando ao runtime do WCF assegurar essa abertura, garantindo que a conexão seja estabelecida antes da mensagem ser enviada para o respectivo serviço. Isso quer dizer que nenhuma mensagem será enviada até que o proxy esteja completamente aberto.

Como estamos em um ambiente multi-threading do lado do cliente e postergando a abertura do proxy somente a partir da primeira chamada para uma operação, teremos aqui um comportamento que poderá causar alguma confusão. Como haverá múltiplas threads executando em paralelo utilizando o mesmo proxy, uma dessas threads ganhará a possibilidade de abrí-lo e, conseqüentemente, enviar a sua requisição para o serviço. Mesmo que o ambiente seja multi-threading, as outras threads que também tem como tarefa a execução de alguma operação ligada ao mesmo proxy, irão aguardar até que a primeira chamada seja completamente realizada.

Todas as requisições que forem realizadas enquanto a primeira delas (a responsável pela aberta do proxy) estiver em execução, serão armazenadas em uma fila (FIFO), executando sequencialmente cada uma dessas requisições solicitadas enquanto a primeira estava sendo processada. As classes (não documentadas) ServiceChannel e CallOnceManager (namespace System.ServiceModel.Channels) são as responsáveis por garantir essa sincronização. A classe CallOnceManager fornece um método chamado CallOnce que gerencia múltiplas requisições. Ao chegar uma requisição para este método, ele verificará se é ou não a primeira requisição solicitada ao proxy; caso seja, ele encaminhará para a execução e, caso não seja, ele irá armazenar essa requisição em uma fila.

Para resolvermos esse problema, podemos invocar as chamadas de forma assíncrona ou chamar explicitamente o método Open do proxy, não delegando a abertura do mesmo somente quando a primeira requisição for solicitada. O exemplo abaixo ilustra isso:

public partial class Form1 : Form
{
    private int _contador;
    private ContratoClient _proxy;

    public Form1()
    {
        InitializeComponent();

        this._proxy = new ContratoClient();
        this._proxy.Open();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        new MethodInvoker(() => 
            this._proxy.EnviarMensagem(++this._contador)).BeginInvoke(null, null);
    }
}

Anúncios

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s