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.
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:
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> ).
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.
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.
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.
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.
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.
Agora é o momento de arrincar as apostas.
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.
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.
O terceiro experimento pretende probar as tendencias reveladas durante o segundo; podemos ver unha maior degradación do punto final sincrónico.
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.
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.
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)?