Dowiedz się więcej o gorynie
Współbieżność to kompozycja niezależnych działań, takich jak praca, którą serwer internetowy wykonuje, gdy zajmuje się wieloma żądaniami użytkowników jednocześnie, ale w sposób autonomiczny. Współbieżność jest obecnie obecna w wielu programach. Serwery internetowe są jednym z przykładów, ale widać również potrzebę współbieżności w przetwarzaniu znacznej ilości danych w partiach.
Go ma dwa style pisania współbieżnych programów. Jednym z nich jest tradycyjny styl, który mógł być używany w innych językach z wątkami. W tym module poznasz styl języka Go, w którym wartości są przekazywane między niezależnymi działaniami znanymi jako goroutines w celu komunikowania procesów .
Jeśli po raz pierwszy poznasz współbieżność, zachęcamy do spędzenia dodatkowego czasu na przejrzeniu każdego fragmentu kodu, który napiszemy do praktyki.
Podejście języka Go do współbieżności
Zazwyczaj największym problemem podczas pisania współbieżnych programów jest udostępnianie danych między procesami. Język Go korzysta z innego podejścia niż inne języki programowania z komunikacją, ponieważ język Go przekazuje dane do tyłu i z powrotem za pośrednictwem kanałów. Takie podejście oznacza, że tylko jedno działanie (goroutine) ma dostęp do danych i nie ma warunku wyścigu zgodnie z projektem. W miarę poznawania goroutines i kanałów w tym module lepiej zrozumiesz podejście współbieżności języka Go.
Podejście języka Go można podsumować w następującym haśle: "Nie przekazuj przez udostępnianie pamięci; zamiast tego udostępnij pamięć, komunikując się". Omówimy to podejście w poniższych sekcjach, ale możesz również dowiedzieć się więcej w wpisie w blogu Go Share Memory By Communicating (Udostępnianie pamięci przez komunikację).
Jak wspomniano wcześniej, go obejmuje również typy pierwotne współbieżności niskiego poziomu. Jednak w tym module omówimy tylko idiotyczne podejście Języka Go do współbieżności.
Zacznijmy od eksplorowania goroutines.
Goroutines
Goroutine jest równoczesnym działaniem w lekkim wątku, a nie tradycyjnym, który znajduje się w systemie operacyjnym. Załóżmy, że masz program, który zapisuje dane wyjściowe i inną funkcję, która oblicza takie elementy, jak dodawanie dwóch liczb. Współbieżny program może mieć kilka goroutine wywołując jednocześnie obie funkcje.
Możemy powiedzieć, że pierwszą goroutiną, którą wykonuje program, jest main()
funkcja. Jeśli chcesz utworzyć kolejną goroutine, musisz użyć słowa kluczowego go
przed wywołaniem funkcji, jak w tym przykładzie:
func main(){
login()
go launch()
}
Alternatywnie można znaleźć, że wiele programów, takich jak używanie funkcji anonimowych do tworzenia goroutines, jak w tym kodzie:
func main(){
login()
go func() {
launch()
}()
}
Aby zobaczyć goroutines w działaniu, napiszmy współbieżny program.
Pisanie programu współbieżnego
Ponieważ chcemy skupić się tylko na współbieżnej części, użyjmy istniejącego programu, który sprawdza, czy punkt końcowy interfejsu API odpowiada, czy nie. Oto kod:
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
start := time.Now()
apis := []string{
"https://management.azure.com",
"https://dev.azure.com",
"https://api.github.com",
"https://outlook.office.com/",
"https://api.somewhereintheinternet.com/",
"https://graph.microsoft.com",
}
for _, api := range apis {
_, err := http.Get(api)
if err != nil {
fmt.Printf("ERROR: %s is down!\n", api)
continue
}
fmt.Printf("SUCCESS: %s is up and running!\n", api)
}
elapsed := time.Since(start)
fmt.Printf("Done! It took %v seconds!\n", elapsed.Seconds())
}
Po uruchomieniu poprzedniego kodu uzyskasz następujące dane wyjściowe:
SUCCESS: https://management.azure.com is up and running!
SUCCESS: https://dev.azure.com is up and running!
SUCCESS: https://api.github.com is up and running!
SUCCESS: https://outlook.office.com/ is up and running!
ERROR: https://api.somewhereintheinternet.com/ is down!
SUCCESS: https://graph.microsoft.com is up and running!
Done! It took 1.658436834 seconds!
Nic nie jest tu zwykłe, ale możemy zrobić lepiej. Być może możemy sprawdzić wszystkie witryny w tym samym czasie? Zamiast trwać prawie dwie sekundy, program może zakończyć się w mniej niż 500 ms.
Zwróć uwagę, że część kodu, którą musimy uruchomić jednocześnie, to ta, która wykonuje wywołanie HTTP do lokacji. Innymi słowy, musimy utworzyć goroutine dla każdego interfejsu API sprawdzanego przez program.
Aby utworzyć goroutine, musimy użyć słowa kluczowego go
przed wywołaniem funkcji. Ale nie mamy tam funkcji. Refaktoryzujmy ten kod i utwórzmy nową funkcję w następujący sposób:
func checkAPI(api string) {
_, err := http.Get(api)
if err != nil {
fmt.Printf("ERROR: %s is down!\n", api)
return
}
fmt.Printf("SUCCESS: %s is up and running!\n", api)
}
Zwróć uwagę, że nie potrzebujemy już słowa kluczowego continue
for
, ponieważ nie znajdujemy się w pętli. Aby zatrzymać przepływ wykonywania funkcji, użyjemy słowa kluczowego return
. Teraz musimy zmodyfikować kod w main()
funkcji, aby utworzyć goroutine na interfejs API, w następujący sposób:
for _, api := range apis {
go checkAPI(api)
}
Uruchom ponownie program i sprawdź, co się stanie.
Wygląda na to, że program nie sprawdza już interfejsów API, prawda? Dane wyjściowe mogą wyglądać podobnie do następujących:
Done! It took 1.506e-05 seconds!
To było szybkie! Co się stało? Zostanie wyświetlony komunikat końcowy z informacją, że program zakończył się, ponieważ go utworzył goroutine dla każdej witryny w pętli i natychmiast poszedł do następnego wiersza.
Mimo że nie wygląda na to, że checkAPI
funkcja jest uruchomiona, jest uruchomiona. To po prostu nie miał czasu, aby zakończyć. Zwróć uwagę, co się stanie w przypadku dołączenia czasomierza uśpienia bezpośrednio po pętli, w następujący sposób:
for _, api := range apis {
go checkAPI(api)
}
time.Sleep(3 * time.Second)
Teraz po ponownym uruchomieniu programu mogą zostać wyświetlone dane wyjściowe podobne do następujących:
ERROR: https://api.somewhereintheinternet.com/ is down!
SUCCESS: https://api.github.com is up and running!
SUCCESS: https://management.azure.com is up and running!
SUCCESS: https://dev.azure.com is up and running!
SUCCESS: https://outlook.office.com/ is up and running!
SUCCESS: https://graph.microsoft.com is up and running!
Done! It took 3.002114573 seconds!
Wygląda na to, że to działa, prawda? Cóż, nie dokładnie. Co zrobić, jeśli chcesz dodać nową witrynę do listy? Być może trzy sekundy nie wystarczy. Jak byś wiedział? Nie można. Musi istnieć lepszy sposób, a to, co omówimy w następnej sekcji, kiedy mówimy o kanałach.