Scopri come goroutine e canali consentono una simultaneità efficiente nei tuoi programmi Go.

La concorrenza è un aspetto cruciale del moderno sviluppo del software in quanto consente ai programmi di gestire in modo efficiente più attività contemporaneamente. È possibile scrivere programmi che eseguono varie operazioni che portano a prestazioni, reattività e utilizzo delle risorse migliorate.

La concorrenza è una delle caratteristiche responsabili della rapida adozione di Go. Il supporto integrato di Go per la programmazione simultanea è considerato semplice e allo stesso tempo aiuta a evitare insidie ​​comuni come race condition e deadlock.

Concorrenza in Go

Go fornisce un solido supporto per la concorrenza attraverso vari meccanismi, tutti disponibili nella sua libreria standard e toolchain. Vai ai programmi raggiungere la concorrenza attraverso goroutine e canali.

Le goroutine sono funzioni leggere che eseguono in modo indipendente che vengono eseguite contemporaneamente ad altre goroutine all'interno dello stesso spazio di indirizzi. Le goroutine consentono a più attività di progredire contemporaneamente senza una gestione esplicita dei thread. Le goroutine sono più leggere dei thread del sistema operativo e Go può eseguire in modo efficiente migliaia o addirittura milioni di goroutine contemporaneamente.

instagram viewer

I canali sono il meccanismo di comunicazione per il coordinamento e la condivisione dei dati tra goroutine. Un canale è un condotto tipizzato che consente alle goroutine di inviare e ricevere valori. I canali forniscono la sincronizzazione per garantire la condivisione sicura dei dati tra le goroutine, prevenendo condizioni di competizione e altri problemi di concorrenza comuni.

Combinando goroutine e canali, Go fornisce un modello di concorrenza potente e diretto che semplifica lo sviluppo di programmi concorrenti mantenendo la sicurezza e l'efficienza. Questi meccanismi consentono di utilizzare facilmente processori multicore e creare applicazioni altamente scalabili e reattive.

Come utilizzare le goroutine per l'esecuzione di codice simultaneo

Il runtime di Go gestisce le goroutine. Le goroutine hanno il loro stack, che consente loro di avere un footprint leggero con una dimensione dello stack iniziale di pochi kilobyte.

Le goroutine vengono multiplexate su diversi thread del sistema operativo dal runtime di Go. Lo scheduler del runtime Go li pianifica sui thread disponibili distribuendo in modo efficiente il carico di lavoro, consentendo l'esecuzione simultanea di più goroutine su meno thread del sistema operativo.

La creazione di goroutine è semplice. Userai il andare parola chiave seguita da una chiamata di funzione per dichiarare le goroutine.

funzprincipale() {
andare funzione1() // Crea ed esegue la goroutine per la funzione1
andare funzione2() // Crea ed esegue la goroutine per la funzione2

// ...
}

funzfunzione1() {
// Codice per funzione1
}

funzfunzione2() {
// Codice per funzione2
}

Quando il programma invoca funzione1() E funzione2() con il andare parola chiave, il runtime Go esegue le funzioni contemporaneamente come goroutine.

Ecco un esempio di utilizzo di una goroutine che stampa il testo sulla console:

pacchetto principale

importare (
"fmt"
"tempo"
)

funzprintText() {
per io:= 1; io <= 5; io++ {
fmt. Stampaln("Stampa testo", io)
tempo. Sonno(1 * tempo. Secondo)
}
}

funzprincipale() {
andare stampaTesto() // Avvia una goroutine per eseguire contemporaneamente la funzione printText

// Esegui altre attività nella goroutine principale
per io:= 1; io <= 5; io++ {
fmt. Stampaln("Esecuzione di altri compiti", io)
tempo. Sonno(500 * tempo. millisecondo)
}

// Attendi che la goroutine finisca
tempo. Sonno(6 * tempo. Secondo)
}

IL printText la funzione stampa ripetutamente del testo sulla console con a per ciclo che viene eseguito cinque volte dopo un ritardo di un secondo tra ogni istruzione con il pacchetto orario.

IL principale la funzione avvia una goroutine chiamando vai stampaTesto, che lancia il printText funziona come una goroutine simultanea separata che consente alla funzione di essere eseguita contemporaneamente al resto del codice nel file principale funzione.

Infine, per garantire che il programma non esca prima del printText goroutine finisce, il tempo. Sonno La funzione mette in pausa la goroutine principale per sei secondi. Negli scenari del mondo reale, utilizzeresti meccanismi di sincronizzazione come canali o gruppi di attesa per coordinare l'esecuzione delle goroutine.

Utilizzo dei canali per la comunicazione e la sincronizzazione

Le goroutine hanno il supporto integrato per la comunicazione e la sincronizzazione attraverso i canali, rendendo la scrittura simultanea codice più semplice rispetto ai thread tradizionali, che spesso richiedono meccanismi di sincronizzazione manuale come blocchi e semafori.

Puoi pensare ai canali come a pipeline per il flusso di dati tra le goroutine. Una goroutine può inviare un valore nel canale e un'altra goroutine può ricevere quel valore dal canale. Questo meccanismo garantisce che lo scambio di dati sia sicuro e sincronizzato.

Userai il operatore per inviare e ricevere dati attraverso i canali.

Ecco un esempio che dimostra l'utilizzo di base dei canali per la comunicazione tra due goroutine:

funzprincipale() {
// Crea un canale senza buffer di tipo stringa
cm := Fare(chancorda)

// Goroutine 1: Invia un messaggio nel canale
andarefunz() {
c "Ciao, Canale!"
}()

// Goroutine 2: riceve il messaggio dal canale
msg := fmt. Println (messaggio) // Output: Ciao, Canale!
}

Il canale in principale la funzione è un canale senza buffer denominato cap creato con il Fare() funzione. La prima goroutine invia il messaggio "Hello, Channel!" nel canale usando il operatore e la seconda goroutine riceve il messaggio dal canale utilizzando lo stesso operatore. Infine il principale la funzione stampa il messaggio ricevuto sulla console.

È possibile definire i canali tipizzati. Specificherai il tipo di canale al momento della creazione. Ecco un esempio che dimostra l'utilizzo di diversi tipi di canale:

funzprincipale() {
// Canale senza buffer
cap1 := Fare(chanint)

// Canale bufferizzato con una capacità di 3
cap2 := Fare(chancorda, 3)

// Invio e ricezione di valori dai canali
ch1 42// Invia un valore in ch1
valore1 := // Riceve un valore da ch1

ch2 "Ciao"// Invia un valore in ch2
valore2 := // Riceve un valore da ch2
}

IL principale funzione crea due canali: cap1 è un canale intero senza buffer, mentre cap2 è un canale stringa bufferizzato con una capacità di 3. È possibile inviare e ricevere valori da e verso questi canali utilizzando il file operatore (i valori devono essere del tipo specificato).

È possibile utilizzare i canali come meccanismi di sincronizzazione per coordinare l'esecuzione della goroutine sfruttando la natura di blocco delle operazioni del canale.

funzprincipale() {
cm := Fare(chanbool)

andarefunz() {
fmt. Stampaln("Goroutine 1")
c VERO// Segnale di completamento
}()

andarefunz() {
// Attendi il segnale di completamento da Goroutine 1
fmt. Stampaln("Goroutine 2")
}()

// Attendi il segnale di completamento da Goroutine 2
fmt. Stampaln("Goroutine principale")
}

IL cap il canale è booleano. Due goroutine vengono eseguite contemporaneamente nel file principale funzione. Goroutine 1 segnala il suo completamento inviando a VERO valore nel canale cap. Goroutine 2 attende il segnale di completamento ricevendo un valore dal canale. Infine, la goroutine principale attende il segnale di completamento dalla goroutine due.

Puoi creare app Web in Go With Gin

Puoi creare app Web ad alte prestazioni in Go with Gin sfruttando al contempo le funzionalità di concorrenza di Go.

Puoi usare Gin per gestire il routing HTTP e il middleware in modo efficiente. Sfrutta il supporto della concorrenza integrato di Go utilizzando goroutine e canali per attività come query di database, chiamate API o altre operazioni di blocco.