Ótima proposta para entender a diferença que faz utilizar as funções assíncronas, porque se o programa parasse e ficasse guardando sem executar mais nada a cada cálculo feito, demoraria bem mais para calcular tudo e consequentemente imprimir as respostas.
Deixando meu código aqui abaixo para caso queiram sugerir melhorias.
import asyncio
import math
numeros = [5, 3, 7, 4, 6]
async def calcular_quadrado(numero):
print(f'O fatorial do número {numero} está sendo calculado...')
await asyncio.sleep(2)
print(f'O fatorial de {numero} é {math.factorial(numero)}')
async def main():
print('Iniciando processo principal na main()')
respostas = []
numeros.sort()
for numero in numeros:
respostas.append(asyncio.create_task(calcular_quadrado(numero)))
await asyncio.gather(*respostas) # O * precendendo a lista permite passar cada elemento da lista (tarefas) de forma individual para o gather.
asyncio.run(main())