paint-brush
Async vs Sync Benchmark (.NET): a diferenza entre os métodos asíncronos e síncronospor@artemmikulich
1,873 lecturas
1,873 lecturas

Async vs Sync Benchmark (.NET): a diferenza entre os métodos asíncronos e síncronos

por Artem Mikulich5m2024/09/21
Read on Terminal Reader

Demasiado longo; Ler

Este artigo mostra a diferenza entre os métodos asíncronos e sincrónicos na práctica. Dúas instancias de langosta independentes están a executarse en dúas máquinas. O número de usuarios crece uniformemente ata o número obxectivo (*Número de usuarios*). A velocidade de crecemento está controlada por un parámetro * Taxa de aparición* (número de usuarios únicos para unirse por segundo)
featured image - Async vs Sync Benchmark (.NET): a diferenza entre os métodos asíncronos e síncronos
Artem Mikulich HackerNoon profile picture

Unha das miñas preguntas favoritas da entrevista é "Que che din palabras como async e await ?" porque abre a oportunidade de ter unha discusión interesante cun entrevistado... Ou non porque flotan sobre este tema. Na miña opinión, é drasticamente importante entender por que usamos esta técnica.


Sinto que moitos desenvolvedores prefiren confiar na declaración "é a mellor práctica" e usar métodos asíncronos cegamente.


Este artigo mostra a diferenza entre os métodos asíncronos e sincrónicos na práctica.

Ferramentas

  • Aplicación .NET Web API (destino de proba)


  • 2 Bases de datos Azure SQL


  • 2 Azure App Service en Windows (alberga a aplicación)


  • Azure App Insights (para reunir métricas)


  • marco de locust (para simular a carga do usuario).

Configuración

Esquema de experimentación

Executarei un benchmark do seguinte xeito. Dúas instancias de langosta independentes están a executarse en dúas máquinas. As instancias de Locust simulan un usuario que fai o seguinte:

  • O usuario do host de langosta 1 chega ao punto final síncrono do App Service 1, recibe a resposta e permanece inactivo durante 0,5-1 segundos (o atraso de tempo exacto é aleatorio). Repítese ata o final do experimento.


  • O usuario do servidor de langosta 2 compórtase exactamente igual, con só unha diferenza: chega ao punto final asíncrono do App Service 2.


Baixo o capó, cada App Service conéctase á súa propia base de datos e executa unha consulta SELECT que leva cinco segundos e devolve algunhas filas de datos. Consulte o código do controlador a continuación para obter referencias. Vou usar Dapper para facer unha chamada á base de datos. Gustaríame chamarlle a atención sobre o feito de que o punto final asíncrono tamén chama á base de datos de forma asíncrona ( QueryAsync<T> ).


Código de servizos da aplicación


Paga a pena engadir que desprego o mesmo código nos dous servizos da aplicación.


Durante a proba, o número de usuarios crece uniformemente ata o número obxectivo ( Número de usuarios ). A velocidade de crecemento está controlada por un parámetro Spawn Rate (número de usuarios únicos para unirse por segundo): canto maior sexa o número, máis rápido se engaden os usuarios. A taxa de aparición está establecida en 10 usuarios/s para todos os experimentos.


Todos os experimentos están limitados a 15 minutos.


Podes atopar detalles da configuración da máquina na sección Detalles técnicos do artigo.

Métricas

  • solicitudes por minuto : mostra o número de solicitudes que realmente procesou a aplicación e devolveu un código de estado.
  • conta de fíos : mostra o número de fíos que consome o servizo da aplicación.
  • tempo medio de resposta, ms


As liñas vermellas fan referencia a asíncronas e as azuis ao punto final síncrono, respectivamente.


Iso é todo sobre a teoría. Imos comezar.

Experimento #1

  • número de usuarios : 75 (por servizo)


Podemos ver que ambos os puntos finais funcionan de xeito similar: xestionando unhas 750 solicitudes por minuto cun tempo medio de resposta de 5200 ms.


Experimento #1. Solicitudes por minuto


O gráfico máis fascinante deste experimento é unha tendencia de fío. Podes ver números significativamente máis altos para o punto final sincrónico (un gráfico azul): máis de 100 fíos.


Experimento #1. Conta de fíos


Non obstante, iso é de esperar e coincide coa teoría: cando se recibe unha solicitude e a aplicación fai unha chamada á base de datos, o fío está bloqueado porque ten que esperar a que se complete unha viaxe de ida e volta. Polo tanto, cando entra outra solicitude, a aplicación ten que producir un novo fío para xestionala.


O gráfico vermello (o reconto de fíos do punto final asíncrono) demostra un comportamento diferente. Cando chega unha solicitude e a aplicación fai unha chamada á base de datos, o fío volve a un grupo de fíos en lugar de ser bloqueado. Polo tanto, cando entra outra solicitude, este fío libre reutilizase. A pesar de que as solicitudes entrantes crecen, a aplicación non precisa ningún fío novo, polo que o seu reconto segue sendo o mesmo.


Paga a pena mencionar a terceira métrica: tempo medio de resposta . Ambos os puntos finais mostraron o mesmo resultado: 5200 ms. Polo tanto, non hai diferenzas en termos de rendemento.


Experimento #1. Resumo


Agora é o momento de arrincar as apostas.

Experimento #2

  • Número de usuarios : 150


Duplicamos a carga. O punto final asíncrono xestiona esta tarefa con éxito: a súa taxa de solicitude por minuto flota en torno a 1500. O irmán síncrono finalmente alcanzou un número comparable de 1410. Pero se observas o gráfico de abaixo, verás que tardou 10 minutos.


O motivo é que o punto final síncrono reacciona á chegada dun novo usuario creando outro fío, pero os usuarios están a ser engadidos ao sistema (só para lembrarche que a taxa de aparición é de 10 usuarios/s) máis rápido do que o servidor web pode adaptarse. Por iso puxo tantas solicitudes en fila ao principio.


Experimento #2. Solicitudes por minuto


Como era de esperar, a métrica de conta de fíos aínda está en torno a 34 para o punto final asíncrono, mentres que aumentou de 102 a 155 para o síncrono. O tempo medio de resposta degradouse de xeito similar á taxa de solicitude por minuto : o tempo de resposta sincrónica foi moito maior ao comezo do experimento. Se mantivera a proba durante 24 horas, os números medios serían pares.


Experimento #2. Resumo


Experimento #3

  • Número de usuarios : 200


O terceiro experimento pretende probar as tendencias reveladas durante o segundo; podemos ver unha maior degradación do punto final sincrónico.


Experimento #3. Resumo


Conclusión

Usar operacións asíncronas en lugar de síncronas non mellora directamente o rendemento nin a experiencia do usuario. En primeiro lugar, mellora a estabilidade e previsibilidade baixo presión. Noutras palabras, eleva o limiar de carga para que o sistema poida procesar máis antes de que se degrade.

Apéndice #1. Detalles técnicos

  • Azure App Service: B1, 100 ACU , 1,75 Gb de memoria, equivalente de computación da serie A.
  • Azure SQL Database: Standard S4: 200 DTU, 500 Mb de almacenamento.
  • Configuración da conexión SQL: Tamaño máximo do grupo = 200.

Apéndice #2. Notas

Para conseguir o resultado máis limpo da proba, debería ter executado probas desde 2 máquinas virtuales situadas na mesma rede onde se atopan os servizos de aplicacións de destino.


Non obstante, asumín que un atraso de rede afectaría a ambas as aplicacións dun xeito máis ou menos similar. Polo tanto, non pode poñer en perigo o obxectivo principal: comparar como se comportan os métodos asíncronos e sincrónicos.

Apéndice #3. Experimento extra

Que piratei para forzar o punto final síncrono a funcionar case como asíncrono e representar o gráfico a continuación (as condicións do experimento son as mesmas que no terceiro: 200 usuarios)?


Experimento extra. Solicitudes por minuto