Pergunta

Eu estou escrevendo um serviço web ASP.NET utilizando C # que tem uma função DoLookup (). Para cada chamada para a função DoLookup () Eu preciso de meu código para executar duas consultas separadas: uma para outro serviço web em um local remoto e um para um banco de dados local. Ambas as consultas têm de completar antes que eu possa compilar os resultados e devolvê-los como a resposta ao método DoLookup. O problema que eu estou lidando com é que eu quero fazer isso o mais eficiente possível, tanto em termos de tempo de resposta e uso de recursos no servidor web. Estamos esperando até vários milhares de consultas por hora. Aqui está uma áspera C # -como visão geral do que eu tenho até agora:

public class SomeService : System.Web.Services.WebService
{
    public SomeResponse DoLookup()
    {
        // Do the lookup at the remote web service and get the response 
        WebResponse wr = RemoteProvider.DoRemoteLookup();   

        // Do the lookup at the local database and get the response
        DBResponse dbr = DoDatabaseLookup();

        SomeResponse resp = new SomeResponse( wr, dbr);

        return resp;
    }
}

O código acima faz tudo sequencialmente e funciona muito bem, mas agora eu quero torná-lo mais escalável. Eu sei que eu posso chamar a função DoRemoteLookup () de forma assíncrona (RemoteProvider tem BeginRemoteLookup / EndRemoteLookup métodos) e que eu também pode fazer o banco de dados de pesquisa de forma assíncrona usando o BeginExecuteNonQuery / métodos EndExecuteNonQuery.

A minha pergunta (finalmente) é esta: como faço para disparar tanto a pesquisa do serviço web remoto e o banco de dados de pesquisa simultaneamente em segmentos separados e garantir que eles tenham tanto concluída antes de retornar a resposta

A razão eu quero executar ambos os pedidos em segmentos separados é que ambos potencialmente têm longos tempos de resposta (1 ou 2 segundos) e eu gostaria de liberar os recursos do servidor web para lidar com outras solicitações enquanto é à espera de respostas. Uma nota adicional - Eu tenho a pesquisa do serviço web remoto que executa de forma assíncrona momento, eu só não queria fazer a amostra acima muito confuso. O que eu estou lutando com está recebendo tanto a pesquisa do serviço remoto e a pesquisa de banco de dados começou ao mesmo tempo e descobrir quando eles têm tanto concluída.

Obrigado por todas as sugestões.

Foi útil?

Solução

Você pode usar um par de AutoResetEvents, um para cada segmento. No final da execução de thread, você chama AutoResetEvents.Set() para disparar o evento.

Depois de desova dos tópicos, você usa WaitAll() com os dois AutoResetEvents. Isso fará com que o segmento para o bloco até que ambos os eventos estão definidos.

A ressalva a esta abordagem é que você deve garantir o Set () é garantia de ser chamado, caso contrário, você vai bloquear para sempre. Além disso garantir que, com tópicos que você exercer a manipulação de exceção adequada, ou você vai inadvertidamente causar mais problemas de desempenho quando exceções unhanded fazer com que seu aplicativo da Web para reiniciar.

MSDN tem código de exemplo em relação ao uso AutoResetEvent.

Outras dicas

assíncronos XML métodos do serviço Web , Como criar métodos do serviço web assíncronos e Como:. Cadeia chamadas assíncronas com um método de serviço web

Mas note o primeiro parágrafo desses artigos:

Este tópico é específico para uma tecnologia de legado. XML Web Services e clientes de serviços Web XML agora deve ser criado usando Windows Communication Foundation (WCF) .


BTW, fazer as coisas da forma como estes artigos dizem é importante porque libera o segmento de trabalho ASP.NET enquanto os de longa execução execuções da tarefa. Caso contrário, você pode estar bloqueando o segmento de trabalho, impedindo-a de manutenção mais pedidos, e impactando escalabilidade.

Assumindo que você pode ter uma função de chamada de retorno, tanto para a solicitação da web e a pesquisa de banco de dados, em seguida, algo ao longo destas linhas podem trabalhar

bool webLookupDone = false;
bool databaseLookupDone = false;

private void FinishedDBLookupCallBack()
{
    databaseLookupDone = true;
    if(webLookupDone)
    {
        FinishMethod();
    }
}

private void FinishedWebLookupCallBack()
{
    webLookupDone = true;
    if(databaseLookupDone)
    {
        FinishMethod();
    }
}

Eu acho que eu não tenho rep suficiente para upvote nem comentários. Portanto, este é um comentário sobre John Saunders resposta e comentário de Alan sobre ele.

Você definitivamente quer ir com a resposta de John se você está preocupado com a escalabilidade e consumo de recursos.

Há duas considerações aqui: Acelerar um pedido individual, e fazer o seu identificador de muitas solicitações simultâneas de forma eficiente. A resposta ex ambos Alan e João alcançar executando as chamadas externas em paralelo.

A última, e parece que foi a sua principal preocupação, é alcançado por não ter linhas bloqueadas em qualquer lugar, ou seja, a resposta de John.

Do not gerar suas próprias threads. Threads são caros, e já existem muitos tópicos no IO ThreadPool que irão lidar com as chamadas externas para você se você usar os métodos asynch fornecidos pelo .NET Framework.

webmethod do seu serviço precisa ser asynch também. Caso contrário, um segmento de trabalho será bloqueado até que as chamadas externas são feitas (ainda é de 1-2 segundos, mesmo que eles correm em paralelo). E você só tem 12 threads por processador lidar com solicitações de entrada (se o seu machine.config é definido de acordo com recomendação .) Ou seja, seria, no máximo, ser capaz de lidar com 12 solicitações simultâneas (vezes o # de CPUs). Por outro lado, se o seu método web é asynch the Begin retornará praticamente instantenously ea linha retornada para o pool segmento de trabalho pronto para lidar com outra solicitação de entrada, enquanto que as suas chamadas externas estão sendo esperou pelo porta de conclusão IO, onde vão ser tratado por threads do pool de threads IO, uma vez que eles retornam.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top