Programmazione asincrona in Python

Mar 06 2023
La programmazione asincrona è un paradigma di programmazione che consente l'esecuzione simultanea e indipendente di molti processi, senza attendere che uno finisca prima di passare a quello successivo. In questo post del blog vedremo cos'è la programmazione asincrona e come usarla in Python.
Programmazione asincrona in Python

La programmazione asincrona è un paradigma di programmazione che consente l'esecuzione simultanea e indipendente di molti processi, senza attendere che uno finisca prima di passare a quello successivo. In questo post del blog vedremo cos'è la programmazione asincrona e come usarla in Python.

Che cos'è la programmazione asincrona?

Nella programmazione sincrona, il computer esegue le istruzioni in ordine sequenziale, bloccando l'esecuzione fino al completamento di un lavoro prima di passare a quello successivo.
La programmazione asincrona, d'altra parte, consente al programma di iniziare un'operazione e poi passare a un'altra senza interrompere l'esecuzione fino al completamento dell'attività originale.

La programmazione asincrona è particolarmente vantaggiosa in circostanze in cui i processi, come l'I/O di rete o le operazioni di database, possono richiedere molto tempo per essere completati. La programmazione asincrona può aiutare ad aumentare le prestazioni e la reattività nelle applicazioni software consentendo al programma di passare ad altre attività in attesa del completamento di un'operazione lenta.

A seconda del linguaggio di programmazione e del framework utilizzato, la programmazione asincrona può essere eseguita utilizzando varie strategie come callback, promesse o parole chiave async/await.

Differenze tra programmazione asincrona e multielaborazione

La principale differenza tra la programmazione asincrona e il multiprocessing è che la programmazione asincrona consente l'esecuzione di operazioni non bloccanti all'interno di un singolo thread, mentre il multiprocessing utilizza molti core o processi per completare il lavoro contemporaneamente.

Differenze tra programmazione asincrona e threading

La principale differenza tra la programmazione asincrona e il threading è che la programmazione asincrona consente operazioni non bloccanti utilizzando un singolo thread, mentre il threading utilizza più thread per eseguire più attività in parallelo.

Per ulteriori informazioni sulle differenze: Treading vs Multiprocessing vs Programmazione asincrona

Come usare Asyncio?

Per prima cosa facciamo un semplice programma che inizia a fare un lavoro alla volta e li finisce.

import time
import asyncio

def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    for job in todo:
        do_job(job)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

main()

# OUTPUT
# Job A started
# Job Adone
# Job B started
# Job B done
# Job C started
# Job C done
# Took: 3.009 seconds

Creazione ed esecuzione di coroutine

Una coroutine è un tipo di funzione che può essere interrotta e ripresa in vari momenti durante l'esecuzione. In altre parole, una coroutine consente di scrivere codice che può essere interrotto, fare qualcos'altro e quindi riprendere da dove era stato interrotto.

Per creare coroutine, dobbiamo usare la asyncparola chiave prima della defparola chiave. Chiamare una coroutine non chiama la funzione che vogliamo eseguire. Crea un compito.

import time
import asyncio

async def do_job(s):
  ...

async def main():
  ...

main()

asyncio.run(main())

se esegui questo codice probabilmente ricevi un errore simile a questo:

RuntimeWarning: coroutine '...' was never awaited

import time
import asyncio

async def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

async def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    for job in todo:
        await do_job(job)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

asyncio.run(main())

# OUTPUT
# Job A started
# Job A done
# Job B started
# Job B done
# Job C started
# Job C done
# Took: 3.009 seconds

await asyncio.sleep(1)

tasks = [asyncio.create_task(do_job(item)) for item in todo]
done, pending = await asyncio.wait(tasks)

import time
import asyncio

async def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

async def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    
    tasks = [asyncio.create_task(do_job(item)) for item in todo]
    done, pending = await asyncio.wait(tasks)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

asyncio.run(main())

# OUTPUT
# Job A started
# Job B started
# Job C started
# Job A done
# Job B done
# Job C done
# Took: 1.009 seconds

Puoi vedere il video per ottenere maggiori informazioni sulla programmazione asincrona in Python. ( Introduzione a Python asincrono | Scrivere un web crawler )