* validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * validated llm translation * fix non-Annotated in llm-prompt * rerun after a few changes in llm-prompt * fix non-Annotated * validated llm translation * fix llm translation * update outdated translations * fix translation for operation IDs * add header link * add missing link * fix line break * fix diff * fix llm translation * fix 'Atualize' to 'Atualizar' * update alternatives.md * update async.md * update fastapi-cli.md * update features.md * update help-fastapi.md * update history-design-future.md * update index.md * update advanced/events.md * update advanced/middleware.md * update advanced/response-cookies.md * update advanced/response-headers.md * update advanced/templates.md * update advanced/testing-websockets.md * update advanced/using-request-directly.md * update advanced/websockets.md * update advanced/security/oauth2-scopes.md * update deployment/cloud.md * update deployment/manually.md * update how-to/custom-request-and-route.md * update how-to/migrate-from-pydantic-v1-to-pydantic-v2.md * update tutorial/background-tasks.md * update tutorial/first-steps.md * update tutorial/handling-errors.md * update tutorial/middleware.md * update tutorial/request-files.md * update tutorial/sql-databases.md * update tutorial/static-files.md * update tutorial/testing.md * update tutorial/dependencies/dependencies-with-yield.md * update advanced/advanced-dependencies.md --------- Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com>
26 KiB
ConcorrĂȘncia e async / await
Detalhes sobre a sintaxe async def para funçÔes de operação de rota e alguns conceitos de cĂłdigo assĂncrono, concorrĂȘncia e paralelismo.
Com pressa?
TL;DR:
Se vocĂȘ estiver utilizando bibliotecas de terceiros que dizem para vocĂȘ chamar as funçÔes com await, como:
results = await some_library()
Então, declare suas funçÔes de operação de rota com async def como:
@app.get('/')
async def read_results():
results = await some_library()
return results
/// note | Nota
VocĂȘ sĂł pode usar await dentro de funçÔes criadas com async def.
///
Se vocĂȘ estĂĄ usando uma biblioteca de terceiros que se comunica com alguma coisa (um banco de dados, uma API, o sistema de arquivos etc.) e nĂŁo tem suporte para utilizar await (esse Ă© atualmente o caso para a maioria das bibliotecas de banco de dados), entĂŁo declare suas funçÔes de operação de rota normalmente, com apenas def, como:
@app.get('/')
def results():
results = some_library()
return results
Se sua aplicação (de alguma forma) nĂŁo tem que se comunicar com nada mais e esperar que o respondam, use async def, mesmo que vocĂȘ nĂŁo precise usar await dentro dela.
Se vocĂȘ simplesmente nĂŁo sabe, use apenas def.
Note: VocĂȘ pode misturar def e async def nas suas funçÔes de operação de rota tanto quanto necessĂĄrio e definir cada função usando a melhor opção para vocĂȘ. FastAPI irĂĄ fazer a coisa certa com elas.
De qualquer forma, em ambos os casos acima, FastAPI irĂĄ trabalhar assincronamente e ser extremamente rĂĄpido.
Mas, seguindo os passos acima, ele serå capaz de fazer algumas otimizaçÔes de performance.
Detalhes Técnicos
VersĂ”es modernas de Python tĂȘm suporte para "cĂłdigo assĂncrono" usando algo chamado "corrotinas", com sintaxe async e await.
Vamos ver aquela frase por partes nas seçÔes abaixo:
- CĂłdigo assĂncrono
asynceawait- Corrotinas
CĂłdigo assĂncrono
CĂłdigo assĂncrono apenas significa que a linguagem đŹ tem um jeito de dizer para o computador / programa đ€ que em certo ponto do cĂłdigo, ele đ€ terĂĄ que esperar algo finalizar em outro lugar. Vamos dizer que esse algo seja chamado "arquivo lento" đ.
EntĂŁo, durante esse tempo, o computador pode ir e fazer outro trabalho, enquanto o "arquivo lento" đ termina.
EntĂŁo o computador / programa đ€ irĂĄ voltar sempre que tiver uma chance, seja porque ele estĂĄ esperando novamente, ou quando ele đ€ terminar todo o trabalho que tem atĂ© esse ponto. E ele đ€ irĂĄ ver se alguma das tarefas que estava esperando jĂĄ terminaram de fazer o que quer que tinham que fazer.
Depois, ele đ€ pega a primeira tarefa para finalizar (vamos dizer, nosso "arquivo lento" đ) e continua o que tem que fazer com ela.
Esse "esperar por algo" normalmente se refere a operaçÔes I/O que são relativamente "lentas" (comparadas à velocidade do processador e da memória RAM), como esperar por:
- dados do cliente para serem enviados através da rede
- dados enviados pelo seu programa serem recebidos pelo cliente através da rede
- conteĂșdo de um arquivo no disco ser lido pelo sistema e entregue ao seu programa
- conteĂșdo que seu programa deu ao sistema para ser escrito no disco
- uma operação em uma API remota
- uma operação no banco de dados finalizar
- uma solicitação no banco de dados retornar o resultado
- etc.
Quanto o tempo de execução é consumido majoritariamente pela espera de operaçÔes I/O, essas operaçÔes são chamadas operaçÔes "limitadas por I/O".
Isso Ă© chamado de "assĂncrono" porque o computador / programa nĂŁo tem que ser "sincronizado" com a tarefa lenta, esperando pelo momento exato em que a tarefa finaliza, enquanto nĂŁo faz nada, para ser capaz de pegar o resultado da tarefa e dar continuidade ao trabalho.
Ao invĂ©s disso, sendo um sistema "assĂncrono", uma vez finalizada, a tarefa pode esperar na fila um pouco (alguns microssegundos) para que o computador / programa finalize o que quer que esteja fazendo, e entĂŁo volte para pegar o resultado e continue trabalhando com ele.
Para "sĂncrono" (contrĂĄrio de "assĂncrono") tambĂ©m Ă© utilizado o termo "sequencial", porquĂȘ o computador / programa segue todos os passos, em sequĂȘncia, antes de trocar para uma tarefa diferente, mesmo se alguns passos envolvam esperar.
ConcorrĂȘncia e hambĂșrgueres
Essa ideia de cĂłdigo assĂncrono descrita acima Ă© Ă s vezes chamada de "concorrĂȘncia". Isso Ă© diferente de "paralelismo".
ConcorrĂȘncia e paralelismo ambos sĂŁo relacionados a "diferentes coisas acontecendo mais ou menos ao mesmo tempo".
Mas os detalhes entre concorrĂȘncia e paralelismo sĂŁo bem diferentes.
Para ver essa diferença, imagine a seguinte histĂłria sobre hambĂșrgueres:
HambĂșrgueres concorrentes
VocĂȘ vai com seu crush na lanchonete, e fica na fila enquanto o caixa pega os pedidos das pessoas na sua frente. đ
EntĂŁo chega a sua vez, vocĂȘ pede dois saborosos hambĂșrgueres para vocĂȘ e seu crush. đđ
O caixa diz alguma coisa para o cozinheiro na cozinha para que eles saibam que tĂȘm que preparar seus hambĂșrgueres (mesmo que ele esteja atualmente preparando os lanches dos outros clientes).
VocĂȘ paga. đž
O caixa te entrega seu nĂșmero de chamada.
Enquanto vocĂȘ espera, vocĂȘ vai com seu crush e pega uma mesa, senta e conversa com seu crush por um bom tempo (jĂĄ que seus hambĂșrgueres sĂŁo muito saborosos, e leva um tempo para serem preparados).
JĂĄ que vocĂȘ estĂĄ sentado na mesa com seu crush, esperando os hambĂșrgueres, vocĂȘ pode passar esse tempo admirando o quĂŁo lindo, maravilhoso e esperto Ă© seu crush âšđâš.
Enquanto espera e conversa com seu crush, de tempos em tempos, vocĂȘ verifica o nĂșmero da chamada exibido no balcĂŁo para ver se jĂĄ Ă© sua vez.
EntĂŁo em algum momento, Ă© finalmente sua vez. VocĂȘ vai ao balcĂŁo, pega seus hambĂșrgueres e volta para a mesa.
VocĂȘ e seu crush comem os hambĂșrgueres e aproveitam o tempo. âš
/// info | Informação
Belas ilustraçÔes de Ketrina Thompson. đš
///
Imagine que vocĂȘ seja o computador / programa đ€ nessa histĂłria.
Enquanto vocĂȘ estĂĄ na fila, vocĂȘ estĂĄ somente ocioso đŽ, esperando por sua vez, sem fazer nada muito "produtivo". Mas a fila Ă© rĂĄpida porque o caixa sĂł estĂĄ pegando os pedidos (nĂŁo os preparando), entĂŁo estĂĄ tudo bem.
EntĂŁo, quando Ă© sua vez, vocĂȘ faz trabalho realmente "produtivo", vocĂȘ processa o menu, decide o que quer, pega a escolha de seu crush, paga, verifica se entregou o cartĂŁo ou a cĂ©dula correta, verifica se foi cobrado corretamente, verifica se seu pedido estĂĄ correto etc.
Mas entĂŁo, embora vocĂȘ ainda nĂŁo tenha os hambĂșrgueres, seu trabalho no caixa estĂĄ "pausado" âž, porque vocĂȘ tem que esperar đ seus hambĂșrgueres ficarem prontos.
Contudo, Ă medida que vocĂȘ se afasta do balcĂŁo e senta na mesa, com um nĂșmero para sua chamada, vocĂȘ pode trocar đ sua atenção para seu crush, e "trabalhar" ⯠đ€ nisso. EntĂŁo vocĂȘ estĂĄ novamente fazendo algo muito "produtivo", como flertar com seu crush đ.
EntĂŁo o caixa đ diz que "seus hambĂșrgueres estĂŁo prontos" colocando seu nĂșmero no balcĂŁo, mas vocĂȘ nĂŁo corre que nem um maluco imediatamente quando o nĂșmero exibido Ă© o seu. VocĂȘ sabe que ninguĂ©m irĂĄ roubar seus hambĂșrgueres porque vocĂȘ tem o seu nĂșmero da chamada, e os outros tĂȘm os deles.
EntĂŁo vocĂȘ espera seu crush terminar a histĂłria que estava contando (terminar o trabalho atual ⯠/ tarefa sendo processada đ€), sorri gentilmente e diz que vocĂȘ estĂĄ indo buscar os hambĂșrgueres âž.
EntĂŁo vocĂȘ vai ao balcĂŁo đ, para a tarefa inicial que agora estĂĄ finalizada âŻ, pega os hambĂșrgueres, agradece, e leva-os para a mesa. Isso finaliza esse passo / tarefa da interação com o balcĂŁo âč. Isso, por sua vez, cria uma nova tarefa, a de "comer hambĂșrgueres" đ âŻ, mas a tarefa anterior de "pegar os hambĂșrgueres" jĂĄ estĂĄ finalizada âč.
HambĂșrgueres paralelos
Agora vamos imaginar que esses nĂŁo sĂŁo "HambĂșrgueres Concorrentes", e sim "HambĂșrgueres Paralelos".
VocĂȘ vai com seu crush na lanchonete paralela.
VocĂȘ fica na fila enquanto vĂĄrios (vamos dizer 8) caixas que tambĂ©m sĂŁo cozinheiros pegam os pedidos das pessoas na sua frente.
Todo mundo na sua frente estĂĄ esperando seus hambĂșrgueres ficarem prontos antes de deixar o caixa porque cada um dos 8 caixas vai e prepara o hambĂșrguer logo apĂłs receber o pedido, antes de pegar o prĂłximo pedido.
EntĂŁo Ă© finalmente sua vez, vocĂȘ pede 2 hambĂșrgueres muito saborosos para vocĂȘ e seu crush.
VocĂȘ paga đž.
O caixa vai para a cozinha.
VocĂȘ espera, na frente do balcĂŁo đ, para que ninguĂ©m pegue seus hambĂșrgueres antes de vocĂȘ, jĂĄ que nĂŁo tem nĂșmeros de chamadas.
Como vocĂȘ e seu crush estĂŁo ocupados nĂŁo permitindo que ninguĂ©m passe na frente e pegue seus hambĂșrgueres assim que estiverem prontos, vocĂȘ nĂŁo pode dar atenção ao seu crush. đ
Isso Ă© trabalho "sĂncrono", vocĂȘ estĂĄ "sincronizado" com o caixa / cozinheiro đšâđł. VocĂȘ tem que esperar đ e estar lĂĄ no exato momento que o caixa / cozinheiro đšâđł terminar os hambĂșrgueres e os der a vocĂȘ, ou entĂŁo, outro alguĂ©m pode pegĂĄ-los.
EntĂŁo seu caixa / cozinheiro đšâđł finalmente volta com seus hambĂșrgueres, depois de um longo tempo esperando đ por eles em frente ao balcĂŁo.
VocĂȘ pega seus hambĂșrgueres e vai para a mesa com seu crush.
VocĂȘs comem os hambĂșrgueres, e o trabalho estĂĄ terminado. âč
NĂŁo houve muita conversa ou flerte jĂĄ que a maior parte do tempo foi gasto esperando đ na frente do balcĂŁo. đ
/// info | Informação
Belas ilustraçÔes de Ketrina Thompson. đš
///
Nesse cenĂĄrio dos hambĂșrgueres paralelos, vocĂȘ Ă© um computador / programa đ€ com dois processadores (vocĂȘ e seu crush), ambos esperando đ e dedicando sua atenção ⯠"esperando no balcĂŁo" đ por um bom tempo.
A lanchonete paralela tem 8 processadores (caixas / cozinheiros), enquanto a lanchonete dos hambĂșrgueres concorrentes tinha apenas 2 (um caixa e um cozinheiro).
Ainda assim, a experiĂȘncia final nĂŁo foi a melhor. đ
Essa seria o equivalente paralelo Ă histĂłria dos hambĂșrgueres. đ
Para um exemplo "mais real", imagine um banco.
AtĂ© recentemente, a maioria dos bancos tinham muitos caixas đšâđŒđšâđŒđšâđŒđšâđŒ e uma grande fila đđđđđđđđ.
Todos os caixas fazendo todo o trabalho, um cliente apĂłs o outro đšâđŒâŻ.
E vocĂȘ tinha que esperar đ na fila por um longo tempo ou poderia perder a vez.
VocĂȘ provavelmente nĂŁo gostaria de levar seu crush đ com vocĂȘ para um rolezinho no banco đŠ.
ConclusĂŁo dos hambĂșrgueres
Nesse cenĂĄrio dos "hambĂșrgueres com seu crush", como tem muita espera, faz mais sentido ter um sistema concorrente âžđâŻ.
Esse é o caso da maioria das aplicaçÔes web.
Muitos, muitos usuĂĄrios, mas seu servidor estĂĄ esperando đ pela sua conexĂŁo nĂŁo tĂŁo boa enviar suas requisiçÔes.
E entĂŁo esperando đ novamente as respostas voltarem.
Essa "espera" đ Ă© medida em microssegundos, mas ainda assim, somando tudo, Ă© um monte de espera no final.
Por isso que faz bastante sentido utilizar cĂłdigo assĂncrono âžđ⯠para APIs web.
Esse tipo de assincronicidade é o que fez NodeJS popular (embora NodeJS não seja paralelo) e essa é a força do Go como uma linguagem de programação.
E esse Ă© o mesmo nĂvel de performance que vocĂȘ tem com o FastAPI.
E como vocĂȘ pode ter paralelismo e assincronicidade ao mesmo tempo, vocĂȘ tem uma maior performance do que a maioria dos frameworks NodeJS testados e lado a lado com Go, que Ă© uma linguagem compilada, mais prĂłxima ao C (tudo graças ao Starlette).
ConcorrĂȘncia Ă© melhor que paralelismo?
NĂŁo! Essa nĂŁo Ă© a moral da histĂłria.
ConcorrĂȘncia Ă© diferente de paralelismo. E Ă© melhor em cenĂĄrios especĂficos que envolvam um monte de espera. Por isso, geralmente Ă© muito melhor do que paralelismo para desenvolvimento de aplicaçÔes web. Mas nĂŁo para tudo.
EntĂŁo, para equilibrar tudo, imagine a seguinte historinha:
VocĂȘ tem que limpar uma casa grande e suja.
Sim, essa Ă© toda a histĂłria.
NĂŁo hĂĄ espera đ em lugar algum, apenas um monte de trabalho para ser feito, em mĂșltiplos cĂŽmodos da casa.
VocĂȘ poderia ter turnos como no exemplo dos hambĂșrgueres, primeiro a sala de estar, entĂŁo a cozinha, mas como vocĂȘ nĂŁo estĂĄ esperando por nada, apenas limpando e limpando, as chamadas nĂŁo afetariam em nada.
Levaria o mesmo tempo para finalizar com ou sem turnos (concorrĂȘncia) e vocĂȘ teria feito o mesmo tanto de trabalho.
Mas nesse caso, se vocĂȘ trouxesse os 8 ex-caixas / cozinheiros / agora-faxineiros, e cada um deles (mais vocĂȘ) pudessem dividir a casa para limpĂĄ-la, vocĂȘs fariam toda a limpeza em paralelo, com a ajuda extra, e terminariam muito mais cedo.
Nesse cenĂĄrio, cada um dos faxineiros (incluindo vocĂȘ) poderia ser um processador, fazendo a sua parte do trabalho.
E a maior parte do tempo de execução é tomada por trabalho real (ao invés de ficar esperando), e o trabalho em um computador é feito pela CPU. Eles chamam esses problemas de "limitados por CPU".
Exemplos comuns de operaçÔes limitadas por CPU são coisas que exigem processamento matemåtico complexo.
Por exemplo:
- Processamento de ĂĄudio ou imagem
- Visão Computacional: uma imagem é composta por milhÔes de pixels, cada pixel tem 3 valores / cores, processar isso normalmente exige alguma computação em todos esses pixels ao mesmo tempo
- Aprendizado de MĂĄquina: Normalmente exige muita multiplicação de matrizes e vetores. Pense numa grande planilha com nĂșmeros e em multiplicar todos eles juntos e ao mesmo tempo.
- Deep Learning: Esse Ă© um subcampo do Aprendizado de MĂĄquina, entĂŁo, o mesmo se aplica. A diferença Ă© que nĂŁo hĂĄ apenas uma grande planilha com nĂșmeros para multiplicar, mas um grande conjunto delas, e em muitos casos, vocĂȘ utiliza um processador especial para construir e/ou usar esses modelos.
ConcorrĂȘncia + Paralelismo: Web + Aprendizado de MĂĄquina
Com FastAPI vocĂȘ pode levar a vantagem da concorrĂȘncia que Ă© muito comum para desenvolvimento web (o mesmo atrativo de NodeJS).
Mas vocĂȘ tambĂ©m pode explorar os benefĂcios do paralelismo e multiprocessamento (tendo mĂșltiplos processadores rodando em paralelo) para trabalhos limitados por CPU como aqueles em sistemas de Aprendizado de MĂĄquina.
Isso, somado ao simples fato que Python é a principal linguagem para Data Science, Aprendizado de Måquina e especialmente Deep Learning, faz do FastAPI uma ótima escolha para APIs web e aplicaçÔes com Data Science / Aprendizado de Måquina (entre muitas outras).
Para ver como alcançar esse paralelismo em produção veja a seção sobre Implantação{.internal-link target=_blank}.
async e await
VersĂ”es modernas do Python tĂȘm um modo muito intuitivo para definir cĂłdigo assĂncrono. Isso faz parecer do mesmo jeito do cĂłdigo normal "sequencial" e fazer a "espera" para vocĂȘ nos momentos certos.
Quando tem uma operação que exigirĂĄ espera antes de dar os resultados e tem suporte para esses novos recursos do Python, vocĂȘ pode escrever assim:
burgers = await get_burgers(2)
A chave aqui Ă© o await. Ele diz ao Python que ele tem que esperar âž por get_burgers(2) finalizar suas coisas đ antes de armazenar os resultados em burgers. Com isso, o Python saberĂĄ que ele pode ir e fazer outras coisas đ ⯠nesse meio tempo (como receber outra requisição).
Para o await funcionar, tem que estar dentro de uma função que suporte essa assincronicidade. Para fazer isso, apenas declare a função com async def:
async def get_burgers(number: int):
# Faz alguma coisa assĂncrona para criar os hambĂșrgueres
return burgers
...ao invés de def:
# Isso nĂŁo Ă© assĂncrono
def get_sequential_burgers(number: int):
# Faz alguma coisa sequencial para criar os hambĂșrgueres
return burgers
Com async def, o Python sabe que, dentro dessa função, ele deve estar ciente das expressĂ”es await, e que isso poderĂĄ "pausar" âž a execução dessa função, e ir fazer outra coisa đ antes de voltar.
Quando vocĂȘ quiser chamar uma função async def, vocĂȘ tem que "esperar" ela. EntĂŁo, isso nĂŁo funcionarĂĄ:
# Isso nĂŁo irĂĄ funcionar, porquĂȘ get_burgers foi definido com: async def
burgers = get_burgers(2)
EntĂŁo, se vocĂȘ estĂĄ usando uma biblioteca que diz que vocĂȘ pode chamĂĄ-la com await, vocĂȘ precisa criar as funçÔes de operação de rota com async def, como em:
@app.get('/burgers')
async def read_burgers():
burgers = await get_burgers(2)
return burgers
Mais detalhes técnicos
VocĂȘ deve ter observado que await pode ser usado somente dentro de funçÔes definidas com async def.
Mas ao mesmo tempo, funçÔes definidas com async def tĂȘm que ser "aguardadas". EntĂŁo, funçÔes com async def podem ser chamadas somente dentro de funçÔes definidas com async def tambĂ©m.
EntĂŁo, sobre o ovo e a galinha, como vocĂȘ chama a primeira função async?
Se vocĂȘ estivar trabalhando com FastAPI nĂŁo terĂĄ que se preocupar com isso, porquĂȘ essa "primeira" função serĂĄ a sua função de operação de rota, e o FastAPI saberĂĄ como fazer a coisa certa.
Mas se vocĂȘ quiser usar async / await sem FastAPI, vocĂȘ tambĂ©m pode fazĂȘ-lo.
Escreva seu prĂłprio cĂłdigo assĂncrono
Starlette (e FastAPI) sĂŁo baseados no AnyIO, o que o torna compatĂvel com ambos o asyncio da biblioteca padrĂŁo do Python, e o Trio.
Em particular, vocĂȘ pode usar diretamente o AnyIO para seus casos de uso avançados de concorrĂȘncia que requerem padrĂ”es mais avançados no seu prĂłprio cĂłdigo.
E atĂ© se vocĂȘ nĂŁo estiver utilizando FastAPI, vocĂȘ tambĂ©m pode escrever suas prĂłprias aplicaçÔes assĂncronas com o AnyIO por ser altamente compatĂvel e ganhar seus benefĂcios (e.g. concorrĂȘncia estruturada).
Eu criei outra biblioteca em cima do AnyIO, como uma fina camada acima, para melhorar um pouco as anotaçÔes de tipo e obter melhor preenchimento automĂĄtico, erros inline, etc. Ela tambĂ©m possui uma introdução amigĂĄvel e um tutorial para ajudar vocĂȘ a entender e escrever seu prĂłprio cĂłdigo async: Asyncer. Seria particularmente Ăștil se vocĂȘ precisar combinar cĂłdigo async com cĂłdigo regular (bloqueador/sĂncrono).
Outras formas de cĂłdigo assĂncrono
Esse estilo de usar async e await Ă© relativamente novo na linguagem.
Mas ele faz o trabalho com cĂłdigo assĂncrono muito mais fĂĄcil.
Essa mesma sintaxe (ou quase a mesma) foi tambĂ©m incluĂda recentemente em versĂ”es modernas do JavaScript (no navegador e NodeJS).
Mas antes disso, controlar cĂłdigo assĂncrono era bem mais complexo e difĂcil.
Nas versĂ”es anteriores do Python, vocĂȘ poderia utilizar threads ou Gevent. Mas o cĂłdigo Ă© bem mais complexo de entender, debugar, e pensar sobre.
Nas versĂ”es anteriores do NodeJS / Navegador JavaScript, vocĂȘ utilizaria "callbacks". O que leva ao "inferno do callback".
Corrotinas
Corrotina é apenas um jeito bonitinho para a coisa que é retornada de uma função async def. O Python sabe que é algo como uma função, que pode começar e que vai terminar em algum ponto, mas que pode ser pausada ➠internamente também, sempre que tiver um await dentro dela.
Mas toda essa funcionalidade de cĂłdigo assĂncrono com async e await Ă© muitas vezes resumida como usando "corrotinas". Ă comparĂĄvel ao principal recurso chave do Go, a "Gorrotina".
ConclusĂŁo
Vamos ver a mesma frase de cima:
VersĂ”es modernas do Python tĂȘm suporte para "cĂłdigo assĂncrono" usando algo chamado "corrotinas", com sintaxe
asynceawait.
Isso pode fazer mais sentido agora. âš
Tudo isso é o que empodera o FastAPI (através do Starlette) e que o faz ter uma performance tão impressionante.
Detalhes muito técnicos
/// warning | Atenção
VocĂȘ pode provavelmente pular isso.
Esses são detalhes muito técnicos de como FastAPI funciona por baixo do capÎ.
Se vocĂȘ tem certo conhecimento tĂ©cnico (corrotinas, threads, blocking etc) e estĂĄ curioso sobre como o FastAPI controla o async def vs normal def, vĂĄ em frente.
///
FunçÔes de operação de rota
Quando vocĂȘ declara uma função de operação de rota com def normal ao invĂ©s de async def, ela Ă© rodada em uma threadpool externa que Ă© entĂŁo aguardada, ao invĂ©s de ser chamada diretamente (jĂĄ que ela bloquearia o servidor).
Se vocĂȘ estĂĄ chegando de outro framework assĂncrono que nĂŁo funciona como descrito acima e vocĂȘ estĂĄ acostumado a definir funçÔes de operação de rota triviais somente de computação com simples def para ter um mĂnimo ganho de performance (cerca de 100 nanosegundos), por favor observe que no FastAPI o efeito pode ser bem o oposto. Nesses casos, Ă© melhor usar async def a menos que suas funçÔes de operação de rota utilizem cĂłdigo que performe bloqueamento I/O.
Ainda, em ambas as situaçÔes, as chances são que o FastAPI ainda serå mais råpido{.internal-link target=_blank} do que (ou ao menos comparåvel a) seu framework anterior.
DependĂȘncias
O mesmo se aplica para as dependĂȘncias{.internal-link target=_blank}. Se uma dependĂȘncia tem as funçÔes com padrĂŁo def ao invĂ©s de async def, ela Ă© rodada no threadpool externo.
Sub-dependĂȘncias
VocĂȘ pode ter mĂșltiplas dependĂȘncias e sub-dependĂȘncias{.internal-link target=_blank} requisitando uma Ă outra (como parĂąmetros de definiçÔes de funçÔes), algumas delas podem ser criadas com async def e algumas com def normal. Isso ainda funcionaria, e aquelas criadas com def normal seriam chamadas em uma thread externa (do threadpool) ao invĂ©s de serem "aguardadas".
Outras funçÔes de utilidade
Qualquer outra função de utilidade que vocĂȘ chame diretamente pode ser criada com def normal ou async def e o FastAPI nĂŁo irĂĄ afetar o modo como vocĂȘ a chama.
Isso estĂĄ em contraste Ă s funçÔes que o FastAPI chama para vocĂȘ: funçÔes de operação de rota e dependĂȘncias.
Se sua função de utilidade Ă© uma função normal com def, ela serĂĄ chamada diretamente (como vocĂȘ a escreve no cĂłdigo), nĂŁo em uma threadpool, se a função Ă© criada com async def entĂŁo vocĂȘ deve esperar por essa função quando vocĂȘ chamĂĄ-la no seu cĂłdigo.
Novamente, esses sĂŁo detalhes muito tĂ©cnicos que provavelmente seriam Ășteis caso vocĂȘ esteja procurando por eles.
Caso contrĂĄrio, vocĂȘ deve ficar bem com as dicas da seção acima: Com pressa?.