Concurrency ermöglicht es uns, mehrere Aufgaben gleichzeitig auszuführen, was zu effizienterem und schnellerem Code führt.
In Go sind Goroutines die grundlegenden Bausteine für Concurrency. Eine Goroutine ist eine leichtgewichtige Ausführungseinheit, die parallel zu anderen Goroutines läuft. Goroutines sind viel leichter als traditionelle Threads und ermöglichen es, Tausende von ihnen gleichzeitig auszuführen.
Um eine Goroutine zu starten, verwenden wir das Schlüsselwort
go gefolgt von einem Funktionsaufruf. Hier ein einfaches
Beispiel:
package main
import (
"fmt"
"time"
)
func sayHello() {
fmt.Println("Hello, Go!")
}
func main() {
go sayHello()
time.Sleep(1 * time.Second)
}In diesem Beispiel:
sayHello, die “Hello, Go!”
auf dem Bildschirm ausgibt.main-Paket starten wir eine Goroutine mit
go sayHello(). Dies bedeutet, dass die Funktion
sayHello parallel zur main-Funktion ausgeführt
wird.time.Sleep(1 * time.Second), um das
Hauptprogramm für eine Sekunde anzuhalten und sicherzustellen, dass die
Goroutine Zeit hat, ihre Arbeit zu erledigen, bevor das Programm
endet.Channels sind Kommunikationsmechanismen, die es Goroutines ermöglichen, miteinander zu kommunizieren und Daten sicher auszutauschen. Ein Channel kann als eine Art Pipeline betrachtet werden, durch die Daten von einer Goroutine zu einer anderen fließen.
Ein Channel wird mit dem make-Befehl erstellt, gefolgt
vom Typ der Daten, die durch den Channel fließen sollen. Hier ein
Beispiel:
package main
import "fmt"
func main() {
messages := make(chan string)
go func() {
messages <- "Hello, Channel!"
}()
msg := <-messages
fmt.Println(msg)
}In diesem Beispiel:
messages, der
Zeichenketten (string) überträgt.messages sendet, indem sie den
Ausdruck messages <- "Hello, Channel!" verwendet.messages mit dem Ausdruck msg := <-messages
und drucken die Nachricht aus.Channels können auch gepuffert sein, was bedeutet, dass sie eine begrenzte Anzahl von Werten speichern können, bevor sie blockieren. Ein gepufferter Channel wird mit einer zusätzlichen Kapazitätsangabe erstellt:
messages := make(chan string, 2)In diesem Beispiel haben wir einen gepufferten Channel mit einer Kapazität von zwei erstellt. Wir können bis zu zwei Nachrichten senden, ohne dass eine empfangende Goroutine erforderlich ist.
package main
import "fmt"
func main() {
messages := make(chan string, 2)
messages <- "Message One"
messages <- "Message Two"
fmt.Println(<-messages)
fmt.Println(<-messages)
}In diesem Beispiel senden wir zwei Nachrichten in den Channel
messages, der eine Kapazität von zwei hat. Dann empfangen
wir die Nachrichten und drucken sie aus.
Das select-Statement in Go ermöglicht es einer
Goroutine, auf mehrere Kommunikationsoperationen gleichzeitig zu warten.
Es ist ähnlich wie ein switch, aber für Channels.
Hier ist ein einfaches Beispiel, um zu zeigen, wie
select funktioniert:
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}In diesem Beispiel:
c1 und
c2.select-Statement, um auf Nachrichten von beiden Channels zu
warten. Wenn eine Nachricht empfangen wird, drucken wir sie aus.Das select-Statement wartet, bis eine der Cases
ausführbar ist, und führt dann diese aus. Wenn mehrere Cases ausführbar
sind, wird eine zufällig ausgewählt.