Sincronizando uma chamada assíncrona em c #

votos
6

Já corri em bastante uma situação embaraçosa em um projeto no trabalho. Precisamos criar usuários em 4 ou 5 serviços diferentes, e configurá-lo de tal maneira que, se um falhar, todos eles falham. Eles estão encapsulados dentro de um bloco de escopo de transação.

Um dos serviços que precisamos para adicionar usuários ao exige telnet, e falsificando alguns dados. Há outras maneiras de fazer isso (que custa dinheiro), mas por enquanto é isso que estamos presos com. Adicionando um utilizador leva aproximadamente 3 minutos. Nós vamos trabalhar para ter que descer significativamente como se pode imaginar, mas isso não é realmente o ponto. Esta chamada é assíncrona e tipo de tem que ser para funcionar corretamente. O punchline é, só pode haver um máximo de 10 conexões para o serviço.

Nosso projeto está sendo configurado para criar usuários em um lote. Então, potencialmente 50 usuários criados ao mesmo tempo. Isto apresenta um problema quando apenas 10 conexões podem ser feitas via telnet, e um usuário processado não é susceptível de levar muito tempo que não seja o serviço de telnet. Agora eu preciso para sincronizar este processo para que o resto não pode continuar até que tenha terminado.

Estamos usando callbacks e delegados com chamadas assíncronas para implementar a funcionalidade. Qual seria a melhor maneira de encapsular a parte assíncrona, e não continuar até que seja concluída?

Devemos criar um loop que só termina quando a chamada for concluída? Há alguma coisa na biblioteca threading que poderia ajudar? Eu nunca trabalhei com fios antes, então esta será uma primeira vez para mim. Quais ferramentas estão lá para ajudar com este problema?

EDITAR:

Se eu usar o / EndInvoke padrão BeginInvoke, vai Asynch chamadas dentro do primeiro delegado honrar a começar / fim também?

Exemplo:

public void dele1(string message) {
    Console.Write(message);
    delegate2 del2 = new delegate2;
    del2();
    Console.Write(End of Delegate 2);
}

public void dele2() {
    // Long Processing
    Console.Write(Delegate 2);
}

public delegate void delegate1(String message);
public delegate void delegate2();

delegate1 del1 = new delegate1(dele1);
del1(Delegate 1).BeginInvoke;
del1().EndInvoke;
Console.Write(End of Delegate 1);

Output // esperado (End Invoke espera até Delegado 2 está terminada):

Delegate 1
End of Delegate 2
Delegate 2
End of Delegate 1

// Ou (End Invoke única aguarda delegado 1 a terminar, mas não quaisquer chamadas delegado internos):

Delegate 1
End of Delegate 2
End of Delegate 1
Delegate 2

Vai acabar espera invocar até o segundo delegado termina o processamento também? Ou será que eu preciso para usar os padrões invoco sobre todas as chamadas de delegado?

Publicado 16/03/2009 em 08:38
fonte usuário
Em outras línguas...                            


6 respostas

votos
7

Você poderia realmente usar monitores, semáforos, ou você poderia até mesmo girar espera até que sua chamada de método assíncrono (s) é feito.

Mas você pode obter isso de graça também. Se você chamar EndInvoke()em um delegado que foi previamente começou com BeginInvoke(), você bloqueia até que o trabalho assíncrono é feito.

Não tenho certeza se isso ajuda, porque você tem que estar usando esse padrão assíncrono. Se isso acontecer, você começa a execução assíncrona (e conversão de Asynchronous volta para chamadas síncronas) gratuitamente.

Confira Chamando Synchronous Métodos de forma assíncrona no MSDN para mais informações sobre este padrão.

Eu espero que isso ajude!

Respondeu 16/03/2009 em 08:58
fonte usuário

votos
2

IAsyncResulttem uma propriedade AsyncWaitHandleque lhe dá um identificador de espera (se estiver disponível), que será sinalizado quando a operação for concluída.

Assim, você pode usar WaitHandle.WaitAll(ou .WaitAny) para executar espera não-girando em muitas alças ao mesmo tempo.

Respondeu 16/03/2009 em 18:15
fonte usuário

votos
2

Parece-me que você quer uma fila ... se houver um pedido em andamento, adicionar à fila (com um Monitor); quando uma chamada for concluída, verifique a fila ...

Respondeu 16/03/2009 em 08:41
fonte usuário

votos
0

Estou um pouco incerto sobre como você está usando TransactionScope (para que eu possa estar fora da base), mas você pode criar DependentTransactions que podem ser repartidos entre os segmentos de trabalho. Sua transação de nível superior não vai comprometer até que todos os DependentTransactions se comprometeram com sucesso e vice-versa com reversão. Descobri isso como uma maneira fácil de fazer tudo ou nada entre threads, desde que a operação que está invocando encapsula comprometer a funcionalidade / rollback (IEnlistmentNotification ou semelhantes).

Respondeu 17/03/2009 em 00:55
fonte usuário

votos
0

Há duas razões para usar tópicos:

  • para tirar proveito dos recursos da CPU, de modo acelerando as coisas
  • para escrever várias máquinas de estados simultâneas como métodos simples, o que os torna mais legível

A desvantagem do uso de fios é:

  • é realmente difícil

Se o gargalo é uma espera três minutos em uma máquina remota, pode ser interessante notar que vários segmentos não estão indo para que você obtenha qualquer vantagem de desempenho. Você poderia escrever toda a thiing single-threaded, a manutenção de um conjunto de até dez "máquina de estado" objetos e movê-los através das etapas de criação do usuário, tudo a partir de um fio, com pouca diferença em todas as mais de desempenho.

Então, o que você está procurando, talvez, é o layout código legível agradável, fazendo a operação de criação do usuário em uma seqüência de chamadas que ler como um método único (que seria se você correu-los como um fio).

Outra maneira de conseguir isso é através de um método iterador, ou seja, contendo yield returndeclarações, que também lhe dá as vantagens de legibilidade-único método. Devo ter ligado a este três vezes na última semana! É o artigo de Jeffrey Richter sobre AsyncEnumerator.

Respondeu 16/03/2009 em 09:04
fonte usuário

votos
0

Você tem poucas opções. Aqui estão algumas idéias -

Primeiro, você poderia usar um ManualResetEvent para "bloquear" o fio condutor até que suas operações assíncronas todos completos. A idéia é ter apenas o segmento principal chamá-lo funcionar, em seguida, fazer event.WaitOne () e a função é responsável por definir o evento.

Alternativamente, você pode tentar usar algo como um Semaphore . Ele é projetado para ajudar nestas situações, desde que você pode limitá-lo a 10 ocorrências simulataneous sem se preocupar com a tentar lidar com isso sozinho. Esta seria provavelmente a minha abordagem preferida.

Respondeu 16/03/2009 em 08:43
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more