Eu tenho um componente de servidor que roda sobre o Zeroc-ICE. Quando eu queria carregar testá-lo, pensei que o uso da biblioteca paralela para criar várias solicitações o faria. Mas isso acaba assim. Usar a biblioteca Parallel (Parallel.For) a partir do C # aparentemente foi mais fácil, mas não parece estar gerando exatamente tudo paralelo no mesmo instante. Portanto, não pode ser a definição para criar N pedidos por segundo. Como devo fazer isso? Eu acho que quem quiser fazer o teste de carga primeiro pensaria sobre isso.
Qual é a maneira eficiente de realmente criar solicitações de N em realmente por segundo?
Outro mito é sobre a programação paralela. Por favor, esclareça-nos, se você usou padrões de programação paralela em C # ou .Net em geral. Imagine que eu tenho 5 processos. Como iniciará todos os cinco processos ao mesmo tempo. O que isso significa para o meu consumo de recursos? Tentei ler muitos dos materiais disponíveis na rede, mas recebo mais e mais perguntas do que elas sendo a resposta para minhas perguntas.
Eu usei Parallel.For e criei N threads e medi o tempo. Então tentei a mesma coisa usando Task.Factory.start para enumeração de tarefas. O tempo medido foi diferente. Então, qual é exatamente a diferença entre usá-los? Quando devo usar as classes correspondentes e com que propósitos exatamente? geralmente temos muitas riquezas, mas não sabemos exatamente como diferenciar uma da outra. Esse é um caso para mim, não sendo possível descobrir por que não devo usar um do outro.
Eu usei a classe de cronômetro para medir esses tempos, que afirma ser o melhor. No cenário em que eu carrego testando um componente, qual seria a maneira de medir o tempo de resposta. O cronômetro parece ser a melhor solução para mim. Quaisquer opiniões são bem-vindas.
ps: Existem muitas ferramentas de teste de carga para aplicativos da web. O meu é um caso personalizado de componentes de servidor. E minha pergunta é mais relacionada à criação de N threads por segundo.
Todas as opiniões são bem-vindas. Só não pense que não é uma questão de programação. Claro que sim. Qualquer programador que queira fazer o controle de qualidade por conta própria deve saber o desempenho de seu produto, em primeira mão. Tentei várias opções e tive que recorrer a como devo fazê-lo?
fonte
Respostas:
Eu não tenho todas as respostas. Espero que eu possa lançar alguma luz sobre isso.
Para simplificar minhas declarações anteriores sobre os modelos de encadeamento do .NET, basta saber que a Parallel Library usa Tasks, e o TaskScheduler for Tasks padrão, usa o ThreadPool. Quanto mais alto você subir na hierarquia (o ThreadPool fica na parte inferior), mais sobrecarga você terá ao criar os itens. Essa sobrecarga extra certamente não significa que é mais lenta, mas é bom saber que está lá. Por fim, o desempenho do seu algoritmo em um ambiente multithread se resume ao seu design. O que executa bem sequencialmente pode não funcionar tão bem em paralelo. Existem muitos fatores envolvidos para fornecer regras rígidas e rápidas, que mudam dependendo do que você está tentando fazer. Como você está lidando com solicitações de rede, tentarei dar um pequeno exemplo.
Deixe-me declarar que não sou especialista em soquetes e não sei quase nada sobre o Zeroc-Ice. Eu sei um pouco sobre operações assíncronas, e é aqui que ele realmente o ajudará. Se você enviar uma solicitação síncrona por meio de um soquete, quando ligar
Socket.Receive()
, seu encadeamento será bloqueado até que uma solicitação seja recebida. Isso não é bom. Seu segmento não pode fazer mais solicitações, pois está bloqueado. Usando Socket.Beginxxxxxx (), a solicitação de E / S será feita e colocada na fila do IRP para o soquete, e seu encadeamento continuará. Isso significa que seu encadeamento pode realmente fazer milhares de solicitações em um loop sem nenhum bloqueio!Se estou entendendo corretamente, você está usando chamadas via Zeroc-Ice em seu código de teste, sem realmente tentar alcançar um ponto de extremidade http. Se for esse o caso, posso admitir que não sei como o Zeroc-Ice funciona. Gostaria, no entanto, sugerem seguindo o conselho aqui , particularmente a parte:
Consider Asynchronous Method Invocation (AMI)
. A página mostra isso:O que parece ser o equivalente ao que descrevi acima usando soquetes .NET. Pode haver outras maneiras de melhorar o desempenho ao tentar fazer muitos envios, mas eu começaria aqui ou com qualquer outra sugestão listada nessa página. Você tem sido muito vago quanto ao design do seu aplicativo, para que eu possa ser mais específico do que estive acima. Lembre-se de que não use mais threads do que o absolutamente necessário para obter o que você precisa, caso contrário, o aplicativo será executado muito mais lentamente do que o necessário.
Alguns exemplos em pseudocódigo (tentaram torná-lo o mais próximo possível do gelo, sem que eu realmente precisasse aprender):
Uma maneira melhor:
Lembre-se de que mais threads! = Melhor desempenho ao tentar enviar soquetes (ou realmente fazer alguma coisa). Os threads não são mágicos, pois resolverão automaticamente qualquer problema em que você esteja trabalhando. Idealmente, você deseja 1 thread por núcleo, a menos que um thread gaste muito tempo aguardando, você pode justificar ter mais. A execução de cada solicitação em seu próprio encadeamento é uma má idéia, pois as alternâncias de contexto ocorrerão e o desperdício de recursos. (Se você quiser ver tudo o que escrevi sobre isso, clique em editar e veja as revisões anteriores deste post. Eu o removi, pois ele parecia apenas obscurecer o principal problema em questão.)
Definitivamente, você pode fazer essas solicitações em threads, se desejar fazer um grande número de solicitações por segundo. No entanto, não exagere com a criação do encadeamento. Encontre um equilíbrio e fique com ele. Você obterá melhor desempenho se usar um modelo assíncrono versus um síncrono.
Espero que ajude.
fonte
Vou pular a pergunta 1) e entrar na segunda posição, pois geralmente é uma maneira aceitável de realizar o que você está procurando. No passado para alcançar n mensagens por segundo que você pode criar um único processo que irá, então, lançar p AppDomains. Cada AppDomain basicamente começa a executar um loop de solicitação assim que um determinado momento é atingido (usando um Timer). Esse tempo deve ser o mesmo para cada AppDomain para garantir que eles comecem a atingir o servidor no mesmo momento.
Algo assim deve funcionar para enviar seus pedidos:
Provavelmente, isso prejudicará o desempenho em qualquer máquina em que você esteja executando, portanto, você sempre poderá implementar um tipo semelhante de loop de várias máquinas diferentes se tiver os recursos (usando processos em vez de domínios de aplicativo).
Para sua terceira pergunta, leia este link em http://www.albahari.com/threading/
Finalmente, um cronômetro deve ser associado a um contador de ocorrências para rastrear a duração e as ocorrências únicas no seu servidor. Isso deve permitir que você faça algumas análises após o fato.
fonte
Não se preocupe com os tópicos, se N for razoavelmente pequeno. Para gerar N solicitações por segundo, use o relógio de parede (
DateTime.Now
). Reserve um tempo antes e depois da solicitação e adicione aSleep
para atrasar a próxima solicitação.Por exemplo, com N = 5 (200 ms):
Isto não é perfeito; você pode achar que isso
Sleep
não é exato. Você pode manter uma contagem contínua de desvios (antes do X'th solicitar, o tempo deve ser X-1 / N depois) e ajustar o período de suspensão de acordo.Quando N se torna muito grande, você simplesmente cria M threads e permite que cada thread gere solicitações N / M da mesma maneira.
fonte
A maneira mais fácil de realizar o teste de carga para qualquer projeto .NET é comprar a edição Ultimate do Visual Studio. Isso vem com ferramentas de teste integradas para ajudar a realizar todos os tipos de testes, incluindo testes de carga. Os testes de carga podem ser pré-formados, criando usuários virtuais em um único PC ou distribuídos por vários para um número maior de usuários; também há um pequeno programa que pode ser instalado nos servidores de destino para retornar dados adicionais durante o teste.
Porém, isso é caro, mas a edição final vem com muitos recursos; portanto, se todos fossem usados, seria um preço mais razoável.
fonte
Se você deseja que todos os threads do X atinjam seu recurso exatamente ao mesmo tempo, você pode colocar cada thread atrás de uma trava de contagem regressiva e especificar um curto período de espera entre as verificações do semáforo.
O C # possui uma implementação (http://msdn.microsoft.com/en-us/library/system.threading.countdownevent(VS.100).aspx).
Ao mesmo tempo, se você estiver testando o sistema com estresse, também poderá verificar as condições de corrida. Nesse caso, você desejaria configurar períodos de suspensão de encadeamento em cada encadeamento que oscilam ao longo do tempo com frequência aleatória e picos / sulcos.
Da mesma forma, talvez você não queira enviar rapidamente várias solicitações rapidamente, pode ter um sucesso maior em colocar seu servidor em mau estado / testar seu desempenho no mundo real, configurando um número menor de threads que gastam mais tempo consumindo e enviando mensagens de volta e adiante no soquete, pois seu servidor provavelmente precisará ativar seus próprios threads para lidar com mensagens lentas em andamento.
fonte