Basi delle goroutine
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 59 di 107.
Una goroutine è un thread di esecuzione leggero gestito dal runtime di Go. A differenza dei thread tradizionali, che consumano una quantità significativa di memoria, le goroutine iniziano con solo pochi kilobyte di spazio nello stack, consentendoti di eseguirne migliaia contemporaneamente.
Per avviare una goroutine, basta inserire la parola chiave go prima di una chiamata di funzione:
func sayHello(name string) {
fmt.Println("Hello,", name)
}
func main() {
go sayHello("Alice") // eseguito contemporaneamente
go sayHello("Bob") // eseguito contemporaneamente
time.Sleep(100 * time.Millisecond)
fmt.Println("Done")
}Quando viene eseguito go sayHello("Alice"), non aspetta che sayHello termini. Invece, passa subito alla riga successiva mentre sayHello viene eseguita in background. Ecco perché abbiamo bisogno di time.Sleep: senza di essa, main terminerebbe prima che le goroutine completino l'esecuzione.
Puoi anche avviare goroutine con funzioni anonime:
go func(msg string) {
fmt.Println(msg)
}("Hello from goroutine")La funzione principale stessa viene eseguita in una goroutine. Quando termina, tutte le altre goroutine vengono terminate immediatamente. Non hanno la possibilità di finire. Usare time.Sleep è una soluzione temporanea; nelle prossime lezioni imparerai tecniche di sincronizzazione adeguate con i channel e i wait group.
Sfida
FacileCostruiamo un esecutore di attività che esegue più attività contemporaneamente usando le goroutine. Creerai un semplice sistema in cui le attività vengono eseguite in background mentre il programma principale continua, mostrando come le goroutine consentano l'esecuzione concorrente.
Organizzerai il codice in due file:
tasks.go: definisci la logica di esecuzione delle attività.Crea una struct
Taskcon i campiName(string) eDuration(int, che rappresenta i millisecondi).Implementa un metodo
Run()suTaskche simula il lavoro attendendo per la durata dell'attività, poi stampa:Task [Name] completedCrea una funzione
RunAllTasks(tasks []Task)che avvia il metodoRun()di ogni attività come goroutine. Dopo aver avviato tutte le goroutine, dovrebbe attendere 500 millisecondi per consentire loro di completare, poi stampare:All tasks launchedmain.go: leggi le informazioni sulle attività e coordina l'esecuzione concorrente.Leggi il numero di attività, poi leggi il nome e la durata di ciascuna attività. Crea le attività e passale a
RunAllTasks. Al termine della sua esecuzione, stampa:Main function done
Verranno forniti i seguenti input:
- Riga 1: numero di attività (intero)
- Righe successive: per ogni attività, due righe: il nome dell'attività, poi la sua durata in millisecondi
Per esempio, dato:
3
Download
100
Process
50
Upload
75Il tuo output dovrebbe mostrare il completamento delle attività (l'ordine può variare a causa della concorrenza), seguito dai messaggi di completamento:
Task Process completed
Task Upload completed
Task Download completed
All tasks launched
Main function doneNota: poiché le goroutine vengono eseguite contemporaneamente, le attività con durata minore terminano in genere per prime. L'ordine di completamento delle attività dipende dalle loro durate: quelle più brevi terminano prima di quelle più lunghe.
Usa time.Sleep con time.Duration e time.Millisecond per le attese. Ricorda che, senza l'attesa in RunAllTasks, la funzione restituirebbe il controllo prima che le goroutine abbiano terminato il loro lavoro.
Provalo tu
package main
import (
"fmt"
)
func main() {
// Leggi il numero di attività
var numTasks int
fmt.Scanln(&numTasks)
// TODO: Crea uno slice per contenere le attività
// TODO: Leggi il nome e la durata di ogni attività
// Per ogni attività:
// - Leggi il nome dell'attività
// - Leggi la durata (come numero intero)
// - Crea un Task e aggiungilo al tuo slice
// TODO: Chiama RunAllTasks con il tuo slice di attività
// TODO: Stampa "Main function done"
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker poolEsercitati da solo: Compilatore Go online