Fan-Out i Fan-In
Rozdzielaj i zbieraj pracę
Fan-Out i Fan-In to bezpłatna lekcja Go Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Go Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Go Academy zawiera 4 lekcji w sumie.
Fan-out i fan-in
Fan-out oznacza uruchomienie kilku goroutines odczytujących dane z jednego kanału i rozdzielających pracę. Fan-in oznacza połączenie wyników kilku goroutines z powrotem w jeden kanał.
- Fan-out rozkłada obciążenie między workerów
- Fan-in konsoliduje wyniki na potrzeby odbiorcy
Etap generatora
Potok rozpoczyna się od generatora — funkcji, która zwraca kanał, przesyła do niego wartości z własnej goroutine, a następnie go zamyka.
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}Fan-out
Aby zastosować fan-out, należy uruchomić kilka goroutines odczytujących dane z tego samego kanału wejściowego. Każda z nich wykonuje tę samą funkcję przetwarzającą i tworzy własny kanał wyjściowy.
in := gen(1, 2, 3, 4, 5)
c1 := square(in)
c2 := square(in)Etap przetwarzania
Etap square odczytuje dane z in, podnosi każdą wartość do kwadratu i wysyła ją do nowego kanału wyjściowego. Wiele instancji tego etapu współdzieli jedno wejście.
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}Fan-in za pomocą merge
Fan-in łączy kilka kanałów w jeden. Obiekt sync.WaitGroup śledzi goroutines obsługujące poszczególne kanały, a goroutine zamykająca czeka na zakończenie wszystkich z nich, zanim zamknie połączone wyjście.
func merge(cs ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for _, c := range cs {
wg.Add(1)
go func(c <-chan int) {
for n := range c {
out <- n
}
wg.Done()
}(c)
}
go func() { wg.Wait(); close(out) }()
return out
}Dlaczego WaitGroup
Każda goroutine łącząca kanały kopiuje dane z jednego kanału wejściowego do out. Nie wolno zamknąć out, dopóki wszystkie kanały wejściowe nie zostaną opróżnione. WaitGroup zlicza aktywne goroutines kopiujące dane, a goroutine zamykająca blokuje się na wg.Wait() do czasu ich zakończenia.
Przechwytywanie zmiennej pętli
W starszych wersjach Go zamknięcie musi przyjmować c jako parametr, aby każda goroutine powiązała własny kanał, a nie współdzieloną zmienną pętli. Jawne przekazanie c pozwala uniknąć klasycznego błędu zmiennej pętli.
Kompletny fan-out i fan-in
Ten program generuje liczby, rozdziela je do dwóch etapów square, a następnie łączy wyniki i oblicza ich sumę.
package main
import (
"fmt"
"sync"
)
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() { for _, n := range nums { out <- n }; close(out) }()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() { for n := range in { out <- n * n }; close(out) }()
return out
}
func merge(cs ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for _, c := range cs {
wg.Add(1)
go func(c <-chan int) { for n := range c { out <- n }; wg.Done() }(c)
}
go func() { wg.Wait(); close(out) }()
return out
}
func main() {
in := gen(1, 2, 3, 4, 5)
c1 := square(in)
c2 := square(in)
total := 0
for n := range merge(c1, c2) {
total += n
}
fmt.Println("sum of squares:", total)
}Kolejność nie jest gwarantowana
Ponieważ dwa etapy square rywalizują o te same dane wejściowe, kolejność elementów na połączonym wyjściu jest niedeterministyczna. Jeśli kolejność ma znaczenie, należy dołączyć do każdego elementu indeks albo użyć jednego etapu.
Kiedy stosować fan-out
Fan-out należy stosować, gdy dany etap jest wąskim gardłem, a jego praca może przebiegać równolegle. Jeśli generator nadrzędny działa wolno, dodanie kolejnych workerów podrzędnych nie pomoże — będą one po prostu bezczynnie czekać.
Backpressure
Niebuforowane kanały zapewniają naturalny mechanizm backpressure: szybki etap blokuje się, gdy wolny odbiorca nie nadąża. Zapobiega to nieograniczonemu wzrostowi zużycia pamięci w całym potoku.
Szybki test
Proszę sprawdzić zrozumienie fan-in.
Podsumowanie
Poznali Państwo fan-out i fan-in:
- Fan-out: wiele goroutines odczytuje dane z jednego kanału
- Fan-in: połączenie wielu kanałów w jeden za pomocą WaitGroup
- Kolejność nie jest zachowywana w równoległych etapach
- Niebuforowane kanały zapewniają backpressure
Często zadawane pytania
Czy lekcja „Fan-Out i Fan-In” jest bezpłatna?
Tak — pełny tekst „Fan-Out i Fan-In” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Go Academy, przejdź na CoddyKit PRO. Kurs Go Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Fan-Out i Fan-In”?
Rozdzielaj i zbieraj pracę Ćwiczysz Go Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Go Academy?
Nie wymagamy żadnego doświadczenia. Go Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Fan-Out i Fan-In”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Go Academy?
Tak. Każda lekcja Go Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wzorzec puli workerów
- Fan-Out i Fan-In
- Etapy potoku
- Kontrolowane zamykanie