> For the complete documentation index, see [llms.txt](https://swift.unicorndonkeys.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://swift.unicorndonkeys.com/guida-al-linguaggio/concorrenza.md).

# Concorrenza (Concurrency)

Esegui operazioni asincrone.

Swift ha un supporto integrato per scrivere codice asincrono e parallelo in modo strutturato. Il *codice asincrono* può essere sospeso e ripreso in seguito, anche se viene eseguita una sola porzione del programma alla volta. Sospendere e riprendere il codice nel tuo programma gli permette di continuare a fare progressi nelle operazioni a breve termine, come l'aggiornamento della sua interfaccia utente, mentre continua a lavorare su operazioni di lunga durata come il recupero di dati tramite la rete o l'analisi di file. Il *codice parallelo* significa che più porzioni di codice vengono eseguite contemporaneamente — per esempio, un computer con un processore a quattro core può eseguire quattro porzioni di codice nello stesso momento, con ciascun core che svolge uno dei compiti. Un programma che usa codice parallelo e asincrono svolge più operazioni alla volta, e sospende le operazioni che sono in attesa di un sistema esterno. Il resto di questo capitolo usa il termine *concorrenza* per riferirsi a questa comune combinazione di codice asincrono e parallelo.

La maggiore flessibilità di pianificazione offerta dal codice parallelo o asincrono comporta anche il costo di una maggiore complessità. Quando scrivi codice concorrente, non sai in anticipo quale codice verrà eseguito nello stesso momento, e potresti non sapere sempre l'ordine in cui il codice verrà eseguito. Un problema comune nel codice concorrente si verifica quando più porzioni di codice cercano di accedere a una qualche porzione di stato mutabile condiviso — questo è noto come *data race* (corsa ai dati). Quando usi il supporto alla concorrenza a livello di linguaggio, Swift rileva e previene le data race, e la maggior parte delle data race produce un errore in fase di compilazione. Alcune data race non possono essere rilevate finché il tuo codice non è in esecuzione; queste data race terminano l'esecuzione del codice. Usi gli actor e l'isolamento per proteggerti dalle data race, come descritto in questo capitolo.

{% hint style="info" %}
**Nota:** Se hai già scritto codice concorrente, potresti essere abituato a lavorare con i thread. Il modello di concorrenza di Swift è costruito sopra i thread, ma non interagisci direttamente con essi. Una funzione asincrona in Swift può cedere il thread su cui è in esecuzione, il che permette a un'altra funzione asincrona di essere eseguita su quel thread mentre la prima funzione è bloccata. Quando una funzione asincrona riprende, Swift non dà alcuna garanzia su quale thread quella funzione verrà eseguita.
{% endhint %}

Sebbene sia possibile scrivere codice concorrente senza usare il supporto del linguaggio di Swift, quel codice tende a essere più difficile da leggere. Per esempio, il codice seguente scarica un elenco di nomi di foto, scarica la prima foto di quell'elenco, e mostra quella foto all'utente:

```swift
listPhotos(inGallery: "Summer Vacation") { photoNames in
    let sortedNames = photoNames.sorted()
    let name = sortedNames[0]
    downloadPhoto(named: name) { photo in
        show(photo)
    }
}
```

Anche in questo semplice caso, poiché il codice deve essere scritto come una serie di gestori di completamento, finisci per scrivere closure annidate. In questo stile, il codice più complesso con un annidamento profondo può diventare rapidamente ingestibile.

## Definire e chiamare funzioni asincrone <a href="#definire-e-chiamare-funzioni-asincrone" id="definire-e-chiamare-funzioni-asincrone"></a>

Una *funzione asincrona* o un *metodo asincrono* è un tipo speciale di funzione o di metodo che può essere sospeso a metà dell'esecuzione. Ciò è in contrasto con le normali funzioni e metodi sincroni, che vengono eseguiti fino al completamento, lanciano un errore, o non restituiscono mai. Una funzione o un metodo asincrono fa comunque una di queste tre cose, ma può anche fermarsi a metà quando è in attesa di qualcosa. All'interno del corpo di una funzione o di un metodo asincrono, contrassegni ciascuno dei punti in cui l'esecuzione può essere sospesa.

Per indicare che una funzione o un metodo è asincrono, scrivi la parola chiave `async` nella sua dichiarazione dopo i suoi parametri, in modo simile a come usi `throws` per contrassegnare una funzione che lancia errori. Se la funzione o il metodo restituisce un valore, scrivi `async` prima della freccia di ritorno (`->`). Per esempio, ecco come potresti recuperare i nomi delle foto di una galleria:

```swift
func listPhotos(inGallery name: String) async -> [String] {
    let result = // ... del codice di rete asincrono ...
    return result
}
```

Per una funzione o un metodo che è sia asincrono sia in grado di lanciare errori, scrivi `async` prima di `throws`.

Quando chiami un metodo asincrono, l'esecuzione viene sospesa finché quel metodo non restituisce il controllo. Scrivi `await` davanti alla chiamata per contrassegnare il possibile punto di sospensione. È come scrivere `try` quando chiami una funzione che lancia errori, per contrassegnare il possibile cambiamento del flusso del programma in caso di errore. All'interno di un metodo asincrono, il flusso di esecuzione può essere sospeso *solo* quando chiami un altro metodo asincrono — la sospensione non è mai implicita o preemptive — il che significa che ogni possibile punto di sospensione è contrassegnato con `await`. Contrassegnare tutti i possibili punti di sospensione nel tuo codice aiuta a rendere il codice concorrente più facile da leggere e da comprendere.

Per esempio, il codice seguente recupera i nomi di tutte le immagini di una galleria e poi mostra la prima immagine:

```swift
let photoNames = await listPhotos(inGallery: "Summer Vacation")
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
let photo = await downloadPhoto(named: name)
show(photo)
```

Poiché le funzioni `listPhotos(inGallery:)` e `downloadPhoto(named:)` devono entrambe effettuare richieste di rete, potrebbero richiedere un tempo relativamente lungo per essere completate. Renderle entrambe asincrone scrivendo `async` prima della freccia di ritorno permette al resto del codice dell'app di continuare a essere eseguito mentre questo codice attende che l'immagine sia pronta.

Per comprendere la natura concorrente dell'esempio qui sopra, ecco un possibile ordine di esecuzione:

1. Il codice inizia l'esecuzione dalla prima riga e prosegue fino al primo `await`. Chiama la funzione `listPhotos(inGallery:)` e sospende l'esecuzione mentre attende che quella funzione restituisca il controllo.
2. Mentre l'esecuzione di questo codice è sospesa, viene eseguito altro codice concorrente dello stesso programma. Per esempio, forse un task in background di lunga durata continua ad aggiornare un elenco di nuove gallerie fotografiche. Anche quel codice viene eseguito fino al successivo punto di sospensione, contrassegnato da `await`, o finché non termina.
3. Dopo che `listPhotos(inGallery:)` ha restituito il controllo, questo codice prosegue l'esecuzione a partire da quel punto. Assegna il valore restituito a `photoNames`.
4. Le righe che definiscono `sortedNames` e `name` sono normale codice sincrono. Poiché nulla è contrassegnato con `await` su queste righe, non ci sono possibili punti di sospensione.
5. Il successivo `await` contrassegna la chiamata alla funzione `downloadPhoto(named:)`. Questo codice mette di nuovo in pausa l'esecuzione finché quella funzione non restituisce il controllo, dando ad altro codice concorrente l'opportunità di essere eseguito.
6. Dopo che `downloadPhoto(named:)` ha restituito il controllo, il suo valore di ritorno viene assegnato a `photo` e poi passato come argomento nella chiamata a `show(_:)`.

I possibili punti di sospensione nel tuo codice contrassegnati con `await` indicano che la porzione di codice corrente potrebbe mettere in pausa l'esecuzione mentre attende che la funzione o il metodo asincrono restituisca il controllo. Questo è chiamato anche *cedere il thread* (yielding the thread) perché, dietro le quinte, Swift sospende l'esecuzione del tuo codice sul thread corrente ed esegue invece altro codice su quel thread. Poiché il codice con `await` deve poter sospendere l'esecuzione, solo alcuni punti del tuo programma possono chiamare funzioni o metodi asincroni:

* Il codice nel corpo di una funzione, di un metodo o di una proprietà asincroni.
* Il codice nel metodo statico `main()` di una struttura, una classe o un'enumerazione contrassegnata con `@main`.
* Il codice in un task figlio non strutturato, come mostrato più avanti in [Concorrenza non strutturata](/guida-al-linguaggio/concorrenza.md#concorrenza-non-strutturata).

Il metodo [`Task.sleep(for:tolerance:clock:)`](https://developer.apple.com/documentation/swift/task/sleep\(for:tolerance:clock:\)) è utile quando si scrive codice semplice per imparare come funziona la concorrenza. Questo metodo sospende il task corrente per almeno la quantità di tempo indicata. Ecco una versione della funzione `listPhotos(inGallery:)` che usa `sleep(for:tolerance:clock:)` per simulare l'attesa di un'operazione di rete:

```swift
func listPhotos(inGallery name: String) async throws -> [String] {
    try await Task.sleep(for: .seconds(2))
    return ["IMG001", "IMG99", "IMG0404"]
}
```

La versione di `listPhotos(inGallery:)` nel codice qui sopra è sia asincrona sia in grado di lanciare errori, perché la chiamata a `Task.sleep(until:tolerance:clock:)` può lanciare un errore. Quando chiami questa versione di `listPhotos(inGallery:)`, scrivi sia `try` sia `await`:

```swift
let photos = try await listPhotos(inGallery: "A Rainy Weekend")
```

Le funzioni asincrone hanno alcune somiglianze con le funzioni che lanciano errori: quando definisci una funzione asincrona o che lancia errori, la contrassegni con `async` o `throws`, e contrassegni le chiamate a quella funzione con `await` o `try`. Una funzione asincrona può chiamare un'altra funzione asincrona, proprio come una funzione che lancia errori può chiamare un'altra funzione che lancia errori.

Tuttavia, c'è una differenza molto importante. Puoi racchiudere il codice che lancia errori in un blocco `do`-`catch` per gestire gli errori, oppure usare `Result` per memorizzare l'errore affinché lo gestisca codice altrove. Questi approcci ti permettono di chiamare funzioni che lanciano errori da codice che non lancia errori. Per esempio:

```swift
func availableRainyWeekendPhotos() -> Result<[String], Error> {
    return Result {
        try listDownloadedPhotos(inGallery: "A Rainy Weekend")
    }
}
```

Al contrario, non esiste un modo sicuro per racchiudere il codice asincrono in modo da poterlo chiamare da codice sincrono e attenderne il risultato. La libreria standard di Swift omette intenzionalmente questa funzionalità non sicura — tentare di implementarla da soli può portare a problemi come race sottili, problemi di threading e deadlock. Quando aggiungi codice concorrente a un progetto esistente, procedi dall'alto verso il basso. Nello specifico, inizia convertendo lo strato di codice più alto affinché usi la concorrenza, e poi inizia a convertire le funzioni e i metodi che esso chiama, procedendo attraverso l'architettura del progetto uno strato alla volta. Non c'è modo di adottare un approccio dal basso verso l'alto, perché il codice sincrono non può mai chiamare codice asincrono.

## Sequenze asincrone <a href="#sequenze-asincrone" id="sequenze-asincrone"></a>

La funzione `listPhotos(inGallery:)` della sezione precedente restituisce in modo asincrono l'intero array in una volta sola, dopo che tutti gli elementi dell'array sono pronti. Un altro approccio consiste nell'attendere un elemento della collezione alla volta usando una *sequenza asincrona*. Ecco come appare l'iterazione su una sequenza asincrona:

```swift
import Foundation

let handle = FileHandle.standardInput
for try await line in handle.bytes.lines {
    print(line)
}
```

Invece di usare un normale ciclo `for`-`in`, l'esempio qui sopra scrive `for` seguito da `await`. Come quando chiami una funzione o un metodo asincrono, scrivere `await` indica un possibile punto di sospensione. Un ciclo `for`-`await`-`in` sospende potenzialmente l'esecuzione all'inizio di ogni iterazione, quando è in attesa che il prossimo elemento sia disponibile.

Nello stesso modo in cui puoi usare i tuoi tipi in un ciclo `for`-`in` aggiungendo la conformità al protocollo [`Sequence`](https://developer.apple.com/documentation/swift/sequence), puoi usare i tuoi tipi in un ciclo `for`-`await`-`in` aggiungendo la conformità al protocollo [`AsyncSequence`](https://developer.apple.com/documentation/swift/asyncsequence).

## Chiamare funzioni asincrone in parallelo <a href="#chiamare-funzioni-asincrone-in-parallelo" id="chiamare-funzioni-asincrone-in-parallelo"></a>

Chiamare una funzione asincrona con `await` esegue una sola porzione di codice alla volta. Mentre il codice asincrono è in esecuzione, il chiamante attende che quel codice termini prima di passare all'esecuzione della riga di codice successiva. Per esempio, per recuperare le prime tre foto di una galleria, potresti attendere tre chiamate alla funzione `downloadPhoto(named:)` come segue:

```swift
let firstPhoto = await downloadPhoto(named: photoNames[0])
let secondPhoto = await downloadPhoto(named: photoNames[1])
let thirdPhoto = await downloadPhoto(named: photoNames[2])

let photos = [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
```

Questo approccio ha un importante svantaggio: anche se il download è asincrono e permette che altro lavoro avvenga mentre procede, viene eseguita una sola chiamata a `downloadPhoto(named:)` alla volta. Ogni foto viene scaricata completamente prima che inizi il download della successiva. Tuttavia, non c'è alcun bisogno che queste operazioni attendano — ogni foto può essere scaricata indipendentemente, o persino nello stesso momento.

Per chiamare una funzione asincrona e lasciarla eseguire in parallelo con il codice circostante, scrivi `async` davanti a `let` quando definisci una costante, e poi scrivi `await` ogni volta che usi la costante.

```swift
async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])

let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
```

In questo esempio, tutte e tre le chiamate a `downloadPhoto(named:)` iniziano senza attendere il completamento della precedente. Se sono disponibili risorse di sistema sufficienti, possono essere eseguite nello stesso momento. Nessuna di queste chiamate di funzione è contrassegnata con `await` perché il codice non si sospende per attendere il risultato della funzione. Invece, l'esecuzione prosegue fino alla riga in cui è definita `photos` — a quel punto, il programma ha bisogno dei risultati di queste chiamate asincrone, quindi scrivi `await` per mettere in pausa l'esecuzione finché tutte e tre le foto non hanno terminato il download.

Ecco come puoi pensare alle differenze tra questi due approcci:

* Chiama le funzioni asincrone con `await` quando il codice nelle righe successive dipende dal risultato di quella funzione. Questo crea lavoro che viene svolto in sequenza.
* Chiama le funzioni asincrone con `async`-`let` quando non hai bisogno del risultato fino a più avanti nel tuo codice. Questo crea lavoro che può essere svolto in parallelo.
* Sia `await` sia `async`-`let` permettono ad altro codice di essere eseguito mentre sono sospesi.
* In entrambi i casi, contrassegni il possibile punto di sospensione con `await` per indicare che l'esecuzione si fermerà, se necessario, finché una funzione asincrona non ha restituito il controllo.

Puoi anche combinare entrambi questi approcci nello stesso codice.

## Task e gruppi di task <a href="#task-e-gruppi-di-task" id="task-e-gruppi-di-task"></a>

Un *task* è un'unità di lavoro che può essere eseguita in modo asincrono come parte del tuo programma. Tutto il codice asincrono viene eseguito come parte di un qualche task. Un task in sé fa una sola cosa alla volta, ma quando crei più task, Swift può pianificarne l'esecuzione simultanea.

La sintassi `async`-`let` descritta nella sezione precedente crea implicitamente un task figlio — questa sintassi funziona bene quando sai già quali task il tuo programma deve eseguire. Puoi anche creare un gruppo di task (un'istanza di [`TaskGroup`](https://developer.apple.com/documentation/swift/taskgroup)) e aggiungere esplicitamente task figli a quel gruppo, il che ti dà più controllo su priorità e cancellazione, e ti permette di creare un numero dinamico di task.

I task sono organizzati in una gerarchia. Ogni task in un dato gruppo di task ha lo stesso task genitore, e ogni task può avere task figli. A causa della relazione esplicita tra task e gruppi di task, questo approccio è chiamato *concorrenza strutturata*. La relazione esplicita genitore-figlio tra i task presenta diversi vantaggi:

* In un task genitore, non puoi dimenticare di attendere il completamento dei suoi task figli.
* Quando imposti una priorità più alta su un task figlio, la priorità del task genitore viene elevata automaticamente.
* Quando un task genitore viene cancellato, anche ciascuno dei suoi task figli viene cancellato automaticamente.
* I valori locali ai task (task-local) si propagano ai task figli in modo efficiente e automatico.

Ecco un'altra versione del codice per scaricare le foto che gestisce un numero qualsiasi di foto:

```swift
await withTaskGroup(of: Data.self) { group in
    let photoNames = await listPhotos(inGallery: "Summer Vacation")
    for name in photoNames {
        group.addTask {
            return await downloadPhoto(named: name)
        }
    }

    for await photo in group {
        show(photo)
    }
}
```

Il codice qui sopra crea un nuovo gruppo di task, e poi crea task figli per scaricare ciascuna foto della galleria. Swift esegue in modo concorrente tanti di questi task quanti le condizioni consentono. Non appena un task figlio termina il download di una foto, quella foto viene mostrata. Non c'è alcuna garanzia sull'ordine in cui i task figli terminano, quindi le foto di questa galleria possono essere mostrate in qualsiasi ordine.

{% hint style="info" %}
**Nota:** Se il codice per scaricare una foto potesse lanciare un errore, chiameresti invece `withThrowingTaskGroup(of:returning:body:)`.
{% endhint %}

Nel listato di codice qui sopra, ogni foto viene scaricata e poi mostrata, quindi il gruppo di task non restituisce alcun risultato. Per un gruppo di task che restituisce un risultato, aggiungi del codice che accumula il suo risultato all'interno della closure che passi a `withTaskGroup(of:returning:body:)`.

```swift
let photos = await withTaskGroup(of: Data.self) { group in
    let photoNames = await listPhotos(inGallery: "Summer Vacation")
    for name in photoNames {
        group.addTask {
            return await downloadPhoto(named: name)
        }
    }

    var results: [Data] = []
    for await photo in group {
        results.append(photo)
    }

    return results
}
```

Come nell'esempio precedente, questo esempio crea un task figlio per ciascuna foto per scaricarla. A differenza dell'esempio precedente, il ciclo `for`-`await`-`in` attende che il task figlio successivo termini, aggiunge il risultato di quel task all'array dei risultati, e poi continua ad attendere finché tutti i task figli non hanno terminato. Infine, il gruppo di task restituisce l'array delle foto scaricate come suo risultato complessivo.

### Cancellazione dei task <a href="#cancellazione-dei-task" id="cancellazione-dei-task"></a>

La concorrenza di Swift usa un modello di cancellazione cooperativo. Ogni task verifica se è stato cancellato nei punti appropriati della sua esecuzione, e risponde alla cancellazione in modo appropriato. A seconda del lavoro che il task sta svolgendo, rispondere alla cancellazione di solito significa una delle cose seguenti:

* Lanciare un errore come `CancellationError`
* Restituire `nil` o una collezione vuota
* Restituire il lavoro parzialmente completato

Scaricare le immagini potrebbe richiedere molto tempo se le immagini sono grandi o la rete è lenta. Per permettere all'utente di interrompere questo lavoro, senza attendere il completamento di tutti i task, i task devono verificare la cancellazione e interrompere l'esecuzione se sono stati cancellati. Ci sono due modi in cui un task può farlo: chiamando il metodo di tipo [`Task.checkCancellation()`](https://developer.apple.com/documentation/swift/task/checkcancellation\(\)), oppure leggendo la proprietà di tipo [`Task.isCancelled`](https://developer.apple.com/documentation/swift/task/iscancelled-swift.type.property). Chiamare `checkCancellation()` lancia un errore se il task è stato cancellato; un task che lancia errori può propagare l'errore all'esterno del task, interrompendo tutto il lavoro del task. Questo ha il vantaggio di essere semplice da implementare e da comprendere. Per una maggiore flessibilità, usa la proprietà `isCancelled`, che ti permette di eseguire lavoro di pulizia come parte dell'interruzione del task, come chiudere le connessioni di rete ed eliminare i file temporanei.

```swift
let photos = await withTaskGroup { group in
    let photoNames = await listPhotos(inGallery: "Summer Vacation")
    for name in photoNames {
        let added = group.addTaskUnlessCancelled {
            Task.isCancelled ? nil : await downloadPhoto(named: name)
        }
        guard added else { break }
    }

    var results: [Data] = []
    for await photo in group {
        if let photo { results.append(photo) }
    }
    return results
}
```

Il codice qui sopra apporta diverse modifiche rispetto alla versione precedente:

* Ogni task viene aggiunto usando il metodo [`TaskGroup.addTaskUnlessCancelled(priority:operation:)`](https://developer.apple.com/documentation/swift/taskgroup/addtaskunlesscancelled\(priority:operation:\)), per evitare di avviare nuovo lavoro dopo la cancellazione.
* Dopo ogni chiamata a `addTaskUnlessCancelled(priority:operation:)`, il codice verifica che il nuovo task figlio sia stato aggiunto. Se il gruppo è stato cancellato, il valore di `added` è `false` — in quel caso, il codice smette di tentare di scaricare altre foto.
* Ogni task verifica la cancellazione prima di iniziare a scaricare la foto. Se è stato cancellato, il task restituisce `nil`.
* Alla fine, il gruppo di task salta i valori `nil` quando raccoglie i risultati. Gestire la cancellazione restituendo `nil` significa che il gruppo di task può restituire un risultato parziale — le foto già scaricate al momento della cancellazione — invece di scartare quel lavoro completato.

{% hint style="info" %}
**Nota:** Per verificare se un task è stato cancellato dall'esterno di quel task, usa la proprietà di istanza [`Task.isCancelled`](https://developer.apple.com/documentation/swift/task/iscancelled-swift.property) invece della proprietà di tipo.
{% endhint %}

Per il lavoro che necessita di una notifica immediata della cancellazione, usa la funzione [`withTaskCancellationHandler(operation:onCancel:isolation:)`](https://developer.apple.com/documentation/swift/withtaskcancellationhandler\(operation:oncancel:isolation:\)). Per esempio:

```swift
let task = Task {
    await withTaskCancellationHandler {
        // ...
    } onCancel: {
        print("Canceled!")
    }
}

// ... qualche tempo dopo...
task.cancel()  // Stampa "Canceled!"
```

Quando usi un gestore di cancellazione, la cancellazione dei task resta comunque cooperativa: il task viene eseguito fino al completamento oppure verifica la cancellazione e si interrompe in anticipo. Poiché il task è ancora in esecuzione quando il gestore di cancellazione si avvia, evita di condividere stato tra il task e il suo gestore di cancellazione, il che potrebbe creare una race condition.

### Concorrenza non strutturata <a href="#concorrenza-non-strutturata" id="concorrenza-non-strutturata"></a>

Oltre agli approcci strutturati alla concorrenza descritti nelle sezioni precedenti, Swift supporta anche la concorrenza non strutturata. A differenza dei task che fanno parte di un gruppo di task, un *task non strutturato* non ha un task genitore. Hai la completa flessibilità di gestire i task non strutturati in qualunque modo il tuo programma richieda, ma sei anche completamente responsabile della loro correttezza.

Per creare un task non strutturato che venga eseguito in modo simile al codice circostante, chiama l'inizializzatore [`Task.init(name:priority:operation:)`](https://developer.apple.com/documentation/swift/task/init\(name:priority:operation:\)-43wmk). Il nuovo task viene eseguito per impostazione predefinita con lo stesso isolamento di actor, la stessa priorità e lo stesso stato task-local del task corrente. Per creare un task non strutturato più indipendente dal codice circostante, noto più specificamente come *task distaccato* (detached task), chiama il metodo statico [`Task.detached(name:priority:operation:)`](https://developer.apple.com/documentation/swift/task/detached\(name:priority:operation:\)-795w1). Il nuovo task viene eseguito per impostazione predefinita senza alcun isolamento di actor e non eredita la priorità né lo stato task-local del task corrente. Entrambe queste operazioni restituiscono un task con cui puoi interagire — per esempio, per attenderne il risultato o per cancellarlo.

```swift
let newPhoto = // ... alcuni dati della foto ...
let handle = Task {
    return await add(newPhoto, toGalleryNamed: "Spring Adventures")
}
let result = await handle.value
```

Per maggiori informazioni sulla gestione dei task distaccati, vedi [`Task`](https://developer.apple.com/documentation/swift/task).

## Isolamento <a href="#isolamento" id="isolamento"></a>

Le sezioni precedenti discutono approcci per suddividere il lavoro concorrente. Quel lavoro può comportare la modifica di dati condivisi, come l'interfaccia utente di un'app. Se parti diverse del tuo codice possono modificare gli stessi dati nello stesso momento, si rischia di creare una data race. Swift ti protegge dalle data race nel tuo codice: ogni volta che leggi o modifichi un dato, Swift garantisce che nessun altro codice lo stia modificando in modo concorrente. Questa garanzia è chiamata *isolamento dei dati*. Ci sono tre modi principali per isolare i dati:

1. I dati immutabili sono sempre isolati. Poiché non puoi modificare una costante, non c'è rischio che altro codice modifichi una costante nello stesso momento in cui la stai leggendo.
2. I dati referenziati solo dal task corrente sono sempre isolati. Una variabile locale può essere letta e scritta in sicurezza perché nessun codice al di fuori del task ha un riferimento a quella memoria, quindi nessun altro codice può modificare quei dati. Inoltre, se catturi la variabile in una closure, Swift garantisce che la closure non venga usata in modo concorrente.
3. I dati protetti da un actor sono isolati se anche il codice che accede a quei dati è isolato rispetto all'actor. Se la funzione corrente è isolata rispetto a un actor, è sicuro leggere e scrivere dati protetti da quell'actor perché qualsiasi altro codice isolato rispetto a quello stesso actor deve attendere il proprio turno prima di essere eseguito.

## Il main actor <a href="#il-main-actor" id="il-main-actor"></a>

Un actor è un oggetto che protegge l'accesso a dati mutabili costringendo il codice ad accedere a turno a quei dati. L'actor più importante in molti programmi è il *main actor* (actor principale). In un'app, il main actor protegge tutti i dati usati per mostrare l'interfaccia utente. Il main actor si alterna nel rendering dell'interfaccia utente, nella gestione degli eventi dell'interfaccia utente, e nell'esecuzione del codice che scrivi e che deve interrogare o aggiornare l'interfaccia utente.

Prima che inizi a usare la concorrenza nel tuo codice, tutto viene eseguito sul main actor. Man mano che identifichi codice di lunga durata o che richiede molte risorse, puoi spostare questo lavoro fuori dal main actor in un modo che resti comunque sicuro e corretto.

{% hint style="info" %}
**Nota:** Il main actor è strettamente legato al main thread (thread principale), ma non sono la stessa cosa. Il main actor ha uno stato mutabile privato, e il main thread serializza l'accesso a quello stato. Quando esegui codice sul main actor, Swift esegue quel codice sul main thread. A causa di questo legame, potresti vedere questi due termini usati in modo intercambiabile. Il tuo codice interagisce con il main actor; il main thread è un dettaglio di implementazione di livello più basso.
{% endhint %}

Ci sono diversi modi per eseguire lavoro sul main actor. Per garantire che una funzione venga sempre eseguita sul main actor, contrassegnala con l'attributo `@MainActor`:

```swift
@MainActor
func show(_: Data) {
    // ... codice dell'interfaccia utente per mostrare la foto ...
}
```

Nel codice qui sopra, l'attributo `@MainActor` sulla funzione `show(_:)` richiede che questa funzione venga eseguita solo sul main actor. All'interno di altro codice in esecuzione sul main actor, puoi chiamare `show(_:)` come funzione sincrona. Tuttavia, per chiamare `show(_:)` da codice che non è in esecuzione sul main actor, devi includere `await` e chiamarla come funzione asincrona, perché il passaggio al main actor introduce un potenziale punto di sospensione. Per esempio:

```swift
func downloadAndShowPhoto(named name: String) async {
    let photo = await downloadPhoto(named: name)
    await show(photo)
}
```

Nel codice qui sopra, sia la funzione `downloadPhoto(named:)` sia la funzione `show(_:)` potrebbero sospendersi quando le chiami. Questo codice mostra anche uno schema comune: eseguire il lavoro di lunga durata e ad alto impiego di CPU in background, e poi passare al main actor per aggiornare l'interfaccia utente. Poiché la funzione `downloadAndShowPhoto(named:)` non si trova sul main actor, anche il lavoro in `downloadPhoto(named:)` non viene eseguito sul main actor. Solo il lavoro in `show(_:)` per aggiornare l'interfaccia utente viene eseguito sul main actor, perché quella funzione è contrassegnata con l'attributo `@MainActor`.

Per garantire che una closure venga eseguita sul main actor, scrivi `@MainActor` prima della lista di cattura e prima di `in`, all'inizio della closure.

```swift
let photo = await downloadPhoto(named: "Trees at Sunrise")
Task { @MainActor in
    show(photo)
}
```

Il codice qui sopra è simile a `downloadAndShowPhoto(named:)` del listato di codice precedente, ma il codice di questo esempio non attende l'aggiornamento dell'interfaccia utente. Puoi anche scrivere `@MainActor` su una struttura, una classe o un'enumerazione per garantire che tutti i suoi metodi e tutti gli accessi alle sue proprietà vengano eseguiti sul main actor:

```swift
@MainActor
struct PhotoGallery {
    var photoNames: [String]
    func drawUI() { /* ... altro codice dell'interfaccia utente ... */ }
}
```

La struttura `PhotoGallery` nel codice qui sopra disegna le foto sullo schermo, usando i nomi della sua proprietà `photoNames` per determinare quali foto mostrare. Poiché `photoNames` influisce sull'interfaccia utente, il codice che la modifica deve essere eseguito sul main actor per serializzare quell'accesso.

Quando costruisci sopra un framework, i protocolli e le classi base di quel framework sono tipicamente già contrassegnati con `@MainActor`, quindi in quel caso di solito non scrivi `@MainActor` sui tuoi tipi. Ecco un esempio semplificato:

```swift
@MainActor
protocol View { /* ... */ }

// Implicitamente @MainActor
struct PhotoGalleryView: View { /* ... */ }
```

Nel codice qui sopra, un framework come SwiftUI definisce il protocollo `View`. Scrivendo `@MainActor` sulla dichiarazione del protocollo, i tipi come `PhotoGalleryView` che sono conformi al protocollo sono anch'essi implicitamente contrassegnati con `@MainActor`. Vedresti lo stesso comportamento se `View` fosse una classe base e `PhotoGalleryView` fosse una sottoclasse — la sottoclasse sarebbe implicitamente contrassegnata con `@MainActor`.

Negli esempi qui sopra, `PhotoGallery` protegge l'intera struttura sul main actor. Per un controllo più granulare, puoi scrivere `@MainActor` solo sulle proprietà o sui metodi a cui è necessario accedere o che è necessario eseguire sul main thread:

```swift
struct PhotoGallery {
    @MainActor var photoNames: [String]
    var hasCachedPhotos = false

    @MainActor func drawUI() { /* ... codice dell'interfaccia utente ... */ }
    func cachePhotos() { /* ... codice di rete ... */ }
}
```

Nella versione di `PhotoGallery` qui sopra, il metodo `drawUI()` disegna le immagini della galleria sullo schermo, quindi deve essere isolato rispetto al main actor. La proprietà `photoNames` non crea direttamente l'interfaccia utente, ma memorizza lo stato che la funzione `drawUI()` usa per disegnare l'interfaccia utente, quindi anche a questa proprietà si deve accedere solo sul main actor. Al contrario, le modifiche alla proprietà `hasCachedPhotos` non interagiscono con l'interfaccia utente, e il metodo `cachePhotos()` non accede ad alcuno stato che ne richieda l'esecuzione sul main actor. Per questo non sono contrassegnati con `@MainActor`.

Come negli esempi precedenti, se usi un framework per costruire la tua interfaccia utente, i property wrapper di quel framework probabilmente contrassegnano già con `@MainActor` le proprietà di stato della tua interfaccia utente. Quando definisci un property wrapper, se la sua proprietà `wrappedValue` è contrassegnata con `@MainActor`, allora anche qualsiasi proprietà a cui applichi quel property wrapper è implicitamente contrassegnata con `@MainActor`.

## Actor <a href="#actor" id="actor"></a>

Swift fornisce per te il main actor — puoi anche definire i tuoi actor. Gli actor ti permettono di condividere in modo sicuro informazioni tra codice concorrente.

Come le classi, gli actor sono tipi riferimento, quindi il confronto tra tipi valore e tipi riferimento in [Le classi sono tipi riferimento](/guida-al-linguaggio/strutture-e-classi.md#le-classi-sono-tipi-riferimento) si applica agli actor oltre che alle classi. A differenza delle classi, gli actor permettono a un solo task alla volta di accedere al loro stato mutabile, il che rende sicuro per il codice di più task interagire con la stessa istanza di un actor. Per esempio, ecco un actor che registra delle temperature:

```swift
actor TemperatureLogger {
    let label: String
    var measurements: [Int]
    private(set) var max: Int

    init(label: String, measurement: Int) {
        self.label = label
        self.measurements = [measurement]
        self.max = measurement
    }
}
```

Introduci un actor con la parola chiave `actor`, seguita dalla sua definizione in una coppia di parentesi graffe. L'actor `TemperatureLogger` ha proprietà a cui può accedere altro codice al di fuori dell'actor, e limita la proprietà `max` in modo che solo il codice all'interno dell'actor possa aggiornare il valore massimo.

Crei un'istanza di un actor usando la stessa sintassi di inizializzazione di strutture e classi. Quando accedi a una proprietà o a un metodo di un actor, usi `await` per contrassegnare il potenziale punto di sospensione. Per esempio:

```swift
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max)
// Stampa "25".
```

In questo esempio, accedere a `logger.max` è un possibile punto di sospensione. Poiché l'actor permette a un solo task alla volta di accedere al suo stato mutabile, se del codice di un altro task sta già interagendo con il logger, questo codice si sospende mentre attende di accedere alla proprietà.

Al contrario, il codice che fa parte dell'actor non scrive `await` quando accede alle proprietà dell'actor. Per esempio, ecco un metodo che aggiorna un `TemperatureLogger` con una nuova temperatura:

```swift
extension TemperatureLogger {
    func update(with measurement: Int) {
        measurements.append(measurement)
        if measurement > max {
            max = measurement
        }
    }
}
```

Il metodo `update(with:)` è già in esecuzione sull'actor, quindi non contrassegna con `await` il suo accesso a proprietà come `max`. Questo metodo mostra anche uno dei motivi per cui gli actor permettono a un solo task alla volta di interagire con il loro stato mutabile: alcuni aggiornamenti allo stato di un actor violano temporaneamente delle invarianti. L'actor `TemperatureLogger` tiene traccia di un elenco di temperature e di una temperatura massima, e aggiorna la temperatura massima quando registri una nuova misurazione. Nel mezzo di un aggiornamento, dopo aver aggiunto la nuova misurazione ma prima di aggiornare `max`, il registratore di temperature si trova in uno stato temporaneamente incoerente. Impedire a più task di interagire con la stessa istanza simultaneamente previene problemi come la seguente sequenza di eventi:

1. Il tuo codice chiama il metodo `update(with:)`. Aggiorna per primo l'array `measurements`.
2. Prima che il tuo codice possa aggiornare `max`, del codice altrove legge il valore massimo e l'array delle temperature.
3. Il tuo codice termina il suo aggiornamento modificando `max`.

In questo caso, il codice in esecuzione altrove leggerebbe informazioni errate perché il suo accesso all'actor si è intercalato nel mezzo della chiamata a `update(with:)` mentre i dati erano temporaneamente non validi. Puoi prevenire questo problema quando usi gli actor di Swift perché consentono una sola operazione alla volta sul loro stato, e perché quel codice può essere interrotto solo nei punti in cui `await` contrassegna un punto di sospensione. Poiché `update(with:)` non contiene alcun punto di sospensione, nessun altro codice può accedere ai dati nel mezzo di un aggiornamento.

Se del codice al di fuori dell'actor tenta di accedere direttamente a quelle proprietà, come si accede alle proprietà di una struttura o di una classe, otterrai un errore in fase di compilazione. Per esempio:

```swift
print(logger.max)  // Errore
```

Accedere a `logger.max` senza scrivere `await` fallisce perché le proprietà di un actor fanno parte dello stato locale isolato di quell'actor. Il codice per accedere a questa proprietà deve essere eseguito come parte dell'actor, il che è un'operazione asincrona e richiede di scrivere `await`. Swift garantisce che solo il codice in esecuzione su un actor possa accedere allo stato locale di quell'actor. Questa garanzia è nota come *isolamento dell'actor*.

I seguenti aspetti del modello di concorrenza di Swift lavorano insieme per rendere più facile ragionare sullo stato mutabile condiviso:

* Il codice compreso tra i possibili punti di sospensione viene eseguito in sequenza, senza possibilità di interruzione da parte di altro codice concorrente. Tuttavia, più porzioni di codice concorrente possono essere eseguite nello stesso momento, quindi altro codice potrebbe essere in esecuzione simultaneamente.
* Il codice che interagisce con lo stato locale di un actor viene eseguito solo su quell'actor.
* Un actor esegue una sola porzione di codice alla volta.

Grazie a queste garanzie, il codice che non include `await` e che si trova all'interno di un actor può effettuare gli aggiornamenti senza il rischio che altri punti del tuo programma osservino lo stato temporaneamente non valido. Per esempio, il codice seguente converte le temperature misurate da Fahrenheit a Celsius:

```swift
extension TemperatureLogger {
    func convertFahrenheitToCelsius() {
        for i in measurements.indices {
            measurements[i] = (measurements[i] - 32) * 5 / 9
        }
    }
}
```

Il codice qui sopra converte l'array delle misurazioni, una alla volta. Mentre l'operazione di mappatura è in corso, alcune temperature sono in Fahrenheit e altre in Celsius. Tuttavia, poiché nessuna parte del codice include `await`, non ci sono potenziali punti di sospensione in questo metodo. Lo stato che questo metodo modifica appartiene all'actor, che lo protegge dal codice che lo legge o lo modifica tranne quando quel codice viene eseguito sull'actor. Ciò significa che non c'è modo per altro codice di leggere un elenco di temperature parzialmente convertite mentre la conversione delle unità è in corso.

Oltre a scrivere codice in un actor che protegge lo stato temporaneamente non valido omettendo i potenziali punti di sospensione, puoi spostare quel codice in un metodo sincrono. Il metodo `convertFahrenheitToCelsius()` qui sopra è un metodo sincrono, quindi è garantito che *non* contenga *mai* potenziali punti di sospensione. Questa funzione incapsula il codice che rende temporaneamente incoerente il modello di dati, e rende più facile per chiunque legga il codice riconoscere che nessun altro codice può essere eseguito prima che la coerenza dei dati venga ripristinata completando il lavoro. È importante che Swift non passi da questo codice all'esecuzione di codice di un'altra parte del programma durante quel periodo di tempo. In futuro, se provi ad aggiungere codice concorrente a questa funzione, introducendo un possibile punto di sospensione, otterrai un errore in fase di compilazione invece di introdurre un bug.

## Global actor <a href="#global-actor" id="global-actor"></a>

Il main actor è un'istanza singleton globale del tipo [`MainActor`](https://developer.apple.com/documentation/swift/mainactor). Un actor può normalmente avere più istanze, ciascuna delle quali fornisce un isolamento indipendente. Per questo motivo dichiari tutti i dati isolati di un actor come proprietà di istanza di quell'actor. Tuttavia, poiché `MainActor` è un singleton — esiste sempre una sola istanza di questo tipo — il tipo da solo è sufficiente a identificare l'actor, il che ti permette di contrassegnare l'isolamento rispetto al main actor usando solo un attributo. Questo approccio ti dà maggiore flessibilità per organizzare il tuo codice nel modo che funziona meglio per te.

Puoi definire i tuoi global actor singleton usando l'attributo `@globalActor`, come descritto in [globalActor](/riferimento-del-linguaggio/attributi.md#globalactor).

## Tipi Sendable <a href="#tipi-sendable" id="tipi-sendable"></a>

I task e gli actor ti permettono di suddividere un programma in parti che possono essere eseguite in modo concorrente e sicuro. All'interno di un task o di un'istanza di un actor, la parte di un programma che contiene stato mutabile, come variabili e proprietà, è chiamata *dominio di concorrenza*. Alcuni tipi di dati non possono essere condivisi tra domini di concorrenza, perché quei dati contengono stato mutabile, ma non proteggono dagli accessi sovrapposti.

Un tipo che può essere condiviso da un dominio di concorrenza a un altro è noto come tipo *sendable*. Per esempio, può essere passato come argomento quando si chiama un metodo di un actor o essere restituito come risultato di un task. Gli esempi precedenti di questo capitolo non hanno discusso della sendability perché usano semplici tipi valore che sono sempre sicuri da condividere per i dati passati tra domini di concorrenza. Al contrario, alcuni tipi non sono sicuri da passare tra domini di concorrenza. Per esempio, una classe che contiene proprietà mutabili e non serializza l'accesso a quelle proprietà può produrre risultati imprevedibili ed errati quando passi istanze di quella classe tra task diversi.

Contrassegni un tipo come sendable dichiarandone la conformità al protocollo `Sendable`. Quel protocollo non ha requisiti di codice, ma ha requisiti semantici che Swift fa rispettare. In generale, ci sono tre modi in cui un tipo può essere sendable:

* Il tipo è un tipo valore, e il suo stato mutabile è costituito da altri dati sendable — per esempio, una struttura con proprietà memorizzate sendable o un'enumerazione con valori associati sendable.
* Il tipo non ha alcuno stato mutabile, e il suo stato immutabile è costituito da altri dati sendable — per esempio, una struttura o una classe che ha solo proprietà di sola lettura.
* Il tipo ha del codice che garantisce la sicurezza del suo stato mutabile, come una classe contrassegnata con `@MainActor` o una classe che serializza l'accesso alle sue proprietà su un particolare thread o coda.

Per un elenco dettagliato dei requisiti semantici, vedi la documentazione di riferimento del protocollo [`Sendable`](https://developer.apple.com/documentation/swift/sendable).

Alcuni tipi sono sempre sendable, come le strutture che hanno solo proprietà sendable e le enumerazioni che hanno solo valori associati sendable. Per esempio:

```swift
struct TemperatureReading: Sendable {
    var measurement: Int
}

extension TemperatureLogger {
    func addReading(from reading: TemperatureReading) {
        measurements.append(reading.measurement)
    }
}

let logger = TemperatureLogger(label: "Tea kettle", measurement: 85)
let reading = TemperatureReading(measurement: 45)
await logger.addReading(from: reading)
```

Poiché `TemperatureReading` è una struttura che ha solo proprietà sendable, e la struttura non è contrassegnata con `public` o `@usableFromInline`, è implicitamente sendable. Ecco una versione della struttura in cui la conformità al protocollo `Sendable` è implicita:

```swift
struct TemperatureReading {
    var measurement: Int
}
```

Per contrassegnare esplicitamente un tipo come non sendable, scrivi una conformità non disponibile a `Sendable`:

```swift
struct FileDescriptor {
    let rawValue: Int
}

@available(*, unavailable)
extension FileDescriptor: Sendable {}
```

Puoi anche usare una conformità non disponibile per sopprimere la conformità implicita a un protocollo, come discusso in [Conformità implicita a un protocollo](/guida-al-linguaggio/protocolli.md#conformita-implicita-a-un-protocollo).
