Podstawy goroutines
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 59 z 107.
Gorutyna to lekki wątek wykonywania zarządzany przez środowisko uruchomieniowe Go. W przeciwieństwie do tradycyjnych wątków, które zużywają dużo pamięci, gorutyny rozpoczynają działanie z zaledwie kilkoma kilobajtami przestrzeni stosu, co pozwala uruchamiać tysiące z nich jednocześnie.
Aby uruchomić gorutynę, po prostu umieść słowo kluczowe go przed wywołaniem funkcji:
func sayHello(name string) {
fmt.Println("Hello,", name)
}
func main() {
go sayHello("Alice") // wykonuje się współbieżnie
go sayHello("Bob") // wykonuje się współbieżnie
time.Sleep(100 * time.Millisecond)
fmt.Println("Done")
}Gdy wykonuje się go sayHello("Alice"), nie czeka, aż sayHello się zakończy. Zamiast tego od razu przechodzi do następnej linii, podczas gdy sayHello działa w tle. Dlatego potrzebujemy time.Sleep — bez niego main zakończyłoby działanie, zanim goroutines się zakończą.
Możesz także uruchamiać goroutines za pomocą funkcji anonimowych:
go func(msg string) {
fmt.Println(msg)
}("Hello from goroutine")Główna funkcja działa w gorutynie. Gdy zwraca wynik, wszystkie pozostałe gorutyny są natychmiast kończone. Nie mają szansy dokończyć działania. Użycie time.Sleep to tymczasowe rozwiązanie; w kolejnych lekcjach poznasz właściwe techniki synchronizacji z użyciem kanałów i grup oczekujących.
Wyzwanie
ŁatwyZbudujmy program do uruchamiania zadań, który wykonuje wiele zadań współbieżnie za pomocą gorutyn. Stworzysz prosty system, w którym zadania działają w tle, podczas gdy główny program jest kontynuowany, demonstrując, jak gorutyny umożliwiają współbieżne wykonywanie.
Rozmieścisz kod w dwóch plikach:
tasks.go: Zdefiniuj logikę wykonywania zadań.Utwórz strukturę
Taskz polamiName(string) iDuration(int, określający czas w milisekundach).Zaimplementuj metodę
Run()dlaTask, która symuluje pracę, usypiając na czas określony dla zadania, a następnie wypisuje:Task [Name] completedUtwórz funkcję
RunAllTasks(tasks []Task), która uruchamia metodęRun()każdego zadania jako gorutynę. Po uruchomieniu wszystkich gorutyn powinna usypiać na 500 milisekund, aby umożliwić im zakończenie, a następnie wypisać:All tasks launchedmain.go: Odczytaj informacje o zadaniach i koordynuj ich współbieżne wykonywanie.Odczytaj liczbę zadań, a następnie nazwę i czas trwania każdego z nich. Utwórz zadania i przekaż je do
RunAllTasks. Po jej zakończeniu wypisz:Main function done
Otrzymasz następujące dane wejściowe:
- Wiersz 1: Liczba zadań (liczba całkowita)
- Kolejne wiersze: Dla każdego zadania dwa wiersze — nazwa zadania, a następnie jego czas trwania w milisekundach
Na przykład, dla danych:
3
Download
100
Process
50
Upload
75Wynik powinien przedstawiać ukończone zadania (kolejność może się różnić ze względu na współbieżność), a następnie komunikaty o zakończeniu:
Task Process completed
Task Upload completed
Task Download completed
All tasks launched
Main function doneUwaga: Ponieważ gorutyny działają współbieżnie, zadania o krótszym czasie trwania zwykle kończą się jako pierwsze. Kolejność kończenia zadań zależy od ich czasu trwania — krótsze zadania kończą się przed dłuższymi.
Użyj time.Sleep z time.Duration i time.Millisecond, aby określić opóźnienia. Pamiętaj, że bez uśpienia w RunAllTasks funkcja zwróciłaby sterowanie, zanim gorutyny zakończą pracę.
Spróbuj swoich sił
package main
import (
"fmt"
)
func main() {
// Wczytaj liczbę zadań
var numTasks int
fmt.Scanln(&numTasks)
// TODO: Utwórz slice do przechowywania zadań
// TODO: Wczytaj nazwę i czas trwania każdego zadania
// Dla każdego zadania:
// - Wczytaj nazwę zadania
// - Wczytaj czas trwania (jako liczbę całkowitą)
// - Utwórz Task i dodaj go do swojego slice
// TODO: Wywołaj RunAllTasks, przekazując swój slice z zadaniami
// TODO: Wypisz "Main function done"
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online