Conta la frequenza delle lettere nei testi usando il calcolo parallelo.
Il parallelismo consiste nel fare in parallelo cose che si possono fare anche in sequenza. Un esempio comune è contare la frequenza delle lettere. Usa il parallelismo per calcolare la frequenza totale di ogni lettera in un elenco di testi.
I task sono l'astrazione principale per scrivere codice asincrono in Lean. Sono leggeri e possono essere eseguiti in parallelo su un altro thread, oppure in modo concorrente sullo stesso thread.
I task possono essere puri o impuri.
I task puri si creano con Task.spawn, che accetta un calcolo puro.
I task impuri si creano da calcoli IO usando, per esempio, IO.asTask, che solleva un IO α in un Task α all'interno della monade IO.
In questo esercizio, la funzione calculateFrequencies è monadica e restituisce un IO (Std.TreeMap Char Nat).
Questo permette di usare task impuri tramite IO.asTask e rende anche possibile generare task puri per calcoli intermedi prima di restituire il valore finale.
Essendo un linguaggio funzionale, in Lean la maggior parte dei valori è persistente, cioè immutabile. Le operazioni che sembrano modificare un valore in realtà ne producono uno nuovo con le modifiche richieste. Questo significa che la memoria può spesso essere condivisa in sicurezza tra i task senza introdurre race condition.
Tieni presente, però, che non tutte le strutture dati sono ugualmente adatte a un uso persistente.
Per esempio, aggiornare un singolo elemento di un Array richiede di solito la copia dell'intero array.
Lo stesso vale per Std.HashSet e Std.HashMap.
Per rendere efficienti queste strutture dati, Lean usa il conteggio dei riferimenti. Finché un valore ha un riferimento unico, gli aggiornamenti possono essere eseguiti in modo distruttivo, evitando copie inutili.
Altre strutture dati, come List, Std.TreeSet e Std.TreeMap, sono progettate per condividere la struttura al loro interno.
Riutilizzano i nodi invariati quando vengono eseguiti gli aggiornamenti, così che più valori possono condividere i riferimenti a quei nodi.
Di conseguenza, modificare una parte della struttura di solito non richiede la copia dell'intero valore.
Questo le rende particolarmente adatte alla condivisione tra i task.
Il tempo di esecuzione di ogni test è misurato in nanosecondi con IO.monoNanosNow e mostrato accanto ai risultati.
Puoi sperimentare approcci diversi e verificare il loro impatto sulle prestazioni di esecuzione.
Iscriviti a Exercism per imparare e padroneggiare Lean con 100 esercizi e il mentoring di persone reali, tutto gratis.
Esploriamo le differenze tra concorrenza e parallelismo, esaminando i diversi approcci adottati da linguaggi come JavaScript, Go, Elixir e Rust.