Uno degli aspetti più popolari del linguaggio di programmazione Go è il suo supporto di prim'ordine per la capacità di un computer di eseguire molti compiti simultaneamente. La capacità di eseguire codice simultaneamente sta diventando sempre più importante nella programmazione, in quanto i computer passano dall'esecuzione più rapida di un singolo flusso di codice all'esecuzione simultanea di molti flussi. Per realizzare programmi più veloci, i programmatori devono progettarli in modo che vengano eseguiti simultaneamente, in modo che ogni elemento concorrente del sistema possa essere eseguito indipendentemente dagli altri.
Due funzionalità di Go, Goroutines e i canali, rendono la concorrenza più facile quando vengono utilizzati insieme. Goroutines offre il tipo primordiale di base per questa capacità. Goroutines sono meno costosi per quanto riguarda lo spazio di memoria, l'interazione tra thread e la connettività di rete. Hanno anche un tempo di avvio migliore rispetto ai thread, che molti linguaggi di programmazione supportano. In sostanza, Go si riferisce a Goroutines come a ciò che Java e altri linguaggi di programmazione chiamano thread.
Cosa sono le Goroutines?
Una goroutine è un semplice thread di implementazione in Golang che viene eseguito simultaneamente al resto del programma. Goroutines sono convenienti quando assomigliano a thread standard, poiché il costo di creazione di una goroutine è estremamente basso. Pertanto, sono ampiamente utilizzate in Go per la programmazione concorrente. Ogni programma è composto da almeno una singola goroutine, nota come goroutine principale. La goroutine principale controlla tutte le altre goroutine; pertanto, se la goroutine principale termina, terminano anche tutte le altre goroutine dello script. La goroutine è sempre attiva in background.
Esempio: Ecco un esempio: si sta scrivendo qualcosa nel proprio quaderno e si ha fame; si fa una pausa e si mangia. Poi si ricomincia a scrivere. Ora state svolgendo due ruoli (scrivere e mangiare) in una finestra temporale considerata occupazione concomitante. Va sottolineato che questi due compiti (scrivere e mangiare) devono comunque essere completati contemporaneamente. Quando gli elementi vengono completati contemporaneamente, si parla di parallelismo (immaginate di usare il cellulare mentre sgranocchiate patatine). La concomitanza comprende l'interazione con molte cose contemporaneamente. Il parallelismo (eseguire molte cose contemporaneamente) è una sottoclasse di questo (non deve essere eseguito nello stesso momento) con una certa tempistica.
Possiamo aggiungere una goroutine applicando la parola chiave go alla chiamata di funzione. Una volta applicata la parola chiave go alla chiamata di funzione, imposteremo la concurrency alla performance. Ma prima, identifichiamo l'effetto dell'applicazione della parola chiave go all'esecuzione. Consideriamo che in un programma ci siano due goroutine. Il testo "package main import" sarà la voce del programma. In Go, un package main import è una dichiarazione di importazione dichiarativa. La goroutine principale (first goroutine) è implicita. Quando si esegue go (f), si forma la seconda goroutine (0). Di solito, quando si esegue una funzione, il nostro software esegue tutti i comandi della funzione principale prima di passare alla riga successiva.
Con una goroutine possiamo eseguire rapidamente la procedura prima di passare alla fase successiva. Di conseguenza, è stato aggiunto un metodo scanln; altrimenti, il codice terminerebbe prima di mostrare tutti i numeri. Goroutines sono semplici da creare e possono essere realizzati in gran numero. Si noterà che quando questo software viene eseguito, le goroutine sembrano operare in modo sequenziale anziché simultaneo.
Vantaggi di Goroutines rispetto ai thread
Goroutines costano poco
Goroutines sono meno costosi di altri processi. La dimensione della pila è di pochi kilobyte e può espandersi o contrarsi per soddisfare le richieste del programma, a differenza dei thread, la cui dimensione della pila deve essere definita ed è permanente.
Ci sono thread multiplexati Goroutines
Sono pochissimi i thread del sistema operativo a cui sono multiplexati. In un programma con centinaia di goroutine, può esserci un solo processo. Il resto delle goroutine viene trasferito al nuovo processo del sistema operativo. Supponiamo che una qualsiasi goroutine di quel processo sia bloccata, ad esempio quando richiede l'intervento dell'utente. Il runtime gestisce ognuno di questi aspetti e a noi sviluppatori viene fornita un'API chiara per gestirli simultaneamente, isolandoci da queste sottili complessità.
Goroutines comunicare usando i canali
Goroutines conversare usando i canali. Sono stati pensati per evitare che si verifichino situazioni di gara quando condividono la memoria pertinente. I canali possono essere paragonati a un condotto che le goroutine usano per interagire.
Cosa sono i canali?
Due goroutine possono interagire tra loro e coordinare le loro operazioni attraverso i canali. Questo software stamperà continuamente "ping". Per designare una forma di canale, il prefisso "chan" è accompagnato dagli elementi trasmessi sul canale". In questo caso, si tratta di stringhe. Sul canale, i messaggi vengono inviati e ricevuti utilizzando l'operatore. "ping" si riferisce all'invio di un "ping".
Il canale viene utilizzato per mantenere sincronizzate le due goroutine. Prima di tentare di inviare un messaggio attraverso il canale, il router attende che la stampante sia pronta ad accettarlo. Il termine per questo è inibizione. Quando si crea un canale, è possibile utilizzare un secondo parametro per la funzione make: c:= make (chan int, 1)
La direzione del canale
Possiamo definire l'orientamento di una forma di canale e parametrizzarla per ricevere o trasmettere. Il segno del metodo Pinger, per esempio, può essere modificato in questo modo:
func pinger(c chan<- string)
C può essere inviato solo ora. Ricevere da c comporterà un errore di codice. Allo stesso modo, possiamo modificare l'uscita in:
func printer(c string -chan)
Un semicanale non ha questi vincoli. Un canale bidirezionale può essere fornito a una procedura che accetta solo canali di sola trasmissione o di sola accettazione, ma non viceversa.
Come creare una goroutine?
Il metodo per lanciare una goroutine è semplice. Applicare la parola chiave "go" alla chiamata di funzione per creare una goroutine che verrà eseguita simultaneamente. In questo caso creeremo una goroutine. Supponiamo di avere un programma contenente due funzioni: una è una funzione di benvenuto e l'altra è la funzione principale.
Quando creiamo una nuova goroutine, il codice welcome () verrà eseguito insieme alla funzione main(). Quando si esegue questo programma, si rimane sorpresi. Questo programma mostra semplicemente il testo dell'operazione principale. Cosa è successo alla prima goroutine o nuova goroutine che abbiamo avviato? Per capire perché questo accade, dobbiamo prima conoscere le due caratteristiche principali delle goroutine.
- La funzione goroutine risponde immediatamente quando creiamo una nuova goroutine. A parte le funzioni, la gestione non si affida alla goroutine, quindi non aspetta che questa completi la sua esecuzione. L'esecuzione viene affidata al blocco di codice successivo alla funzione goroutine. Per questo motivo, qualsiasi parametro fornito dalla goroutine viene ignorato.
- Eventuali goroutine aggiuntive devono essere eseguite in contemporanea con la goroutine principale. Se la goroutine principale fallisce, il programma si chiude e non vengono eseguite altre goroutine.
Ora si capisce perché il nostro codice non funziona. Dopo la chiamata a go welcome(), il controllo è stato trasferito alla riga di codice seguente prima di attendere il completamento della goroutine hello e l'uscita della funzione main. La goroutine principale moriva perché non c'era alcuno script da eseguire, impedendo l'esecuzione della goroutine hello.
Abbiamo invocato la tecnica sleep (time.sleep(1 * time.second)) per mettere in pausa la goroutine per 1 secondo. La funzione di benvenuto () ha ora tempo sufficiente per essere completata prima che la goroutine principale esca. Questo software scrive inizialmente "welcome goroutine" e poi attende un secondo prima di stampare la funzione principale. Utilizziamo la tecnica sleep nella goroutine principale per metterla in pausa per un momento e permettere alle altre goroutine di completarsi.
Creazione di più programmi Goroutines
Avvieremo un altro programma per creare più goroutine. Possiamo iniziare creando due goroutine che verranno eseguite in parallelo. Queste due goroutine sono la goroutine numeri[go numbers()] e la goroutine alfabeto [go alphabets ()].
La goroutine dei numeri rimane per 250 ms prima di stampare 1, si riposa di nuovo prima di stampare 2 e così via fino a quando non produce 5. Analogamente, la goroutine alfanumerica visualizza le lettere dalla a alla e e attende 400 millisecondi. Infine, la goroutine principale crea i numeri interi e i caratteri alfanumerici, fa una pausa e termina la goroutine principale.
Errori frequenti nella programmazione concorrente
- Assenza di sincronizzazioni quando sono necessarie
- Utilizzo di chiamate time. Sleep per eseguire le sincronizzazioni
- Lasciare le goroutine a penzoloni copiare i valori dei tipi del pacchetto standard di sincronizzazione
- Chiamare la sincronizzazione
- Gruppo di attesa
- Aggiungere metodi in punti sbagliati
- Utilizzare i canali come canali di chiusura domani, non dall'ultima goroutine mittente funzionante
Conclusione
In questo articolo abbiamo sviluppato un programma che utilizzava la parola chiave go per lanciare una goroutine e più goroutine che stampavano simultaneamente numeri interi. Dopo aver avviato il programma, abbiamo creato un nuovo canale, che abbiamo poi utilizzato per produrre numeri in una goroutine e passarli a un'altra goroutine in modo che potessero essere visualizzati sullo schermo. Come dimostrazione finale di come avviare una goroutine per velocizzare le applicazioni su sistemi multi-core, abbiamo lanciato simultaneamente molte goroutine "di stampa".
Come sappiamo, le goroutine sono un modo per eseguire compiti in modo più rapido ed efficiente. Questa è una delle procedure di distribuzione offerte da AppMaster per migliorare la funzionalità della vostra applicazione. Con AppMaster, anche le persone con scarse o nulle conoscenze di programmazione possono completare compiti che sarebbero difficili da portare a termine con la codifica manuale.
AppMaster è una no-code è una piattaforma in grado di creare applicazioni mobili e web e un backend. Un dato interessante è che AppMaster crea un backend da Go a 22.000 linee al secondo ed è possibile accedere al codice sorgente.