Sincronizare
Utilizarea canalelor ne oferă posibilități de sincronizare între diferite gorutine. De exemplu, o gorutină efectuează o anumită acțiune, iar rezultatul acesteia este utilizat de o altă gorutină. În acest sens, putem folosi canalele pentru sincronizare. De exemplu, o gorutină calculează factorialul unui număr, iar rezultatul este afișat într-o altă gorutină:
package main
import "fmt"
func main() {
intCh := make(chan int)
go factorial(5, intCh)
fmt.Println(<-intCh)
}
func factorial(n int, ch chan int){
result := 1
for i := 1; i <= n; i++{
result *= i
}
ch <- result
}
Canalul nu trebuie neapărat să conțină date care reprezintă un anumit rezultat de la care depinde continuarea execuției gorutinei. Uneori, acesta poate fi un obiect gol, de exemplu, o structură goală, care este necesară doar pentru sincronizarea gorutinelor:
package main
import "fmt"
func main() {
results := make(map[int]int)
structCh := make(chan struct{})
go factorial(5, structCh, results)
<-structCh // așteptăm închiderea canalului structCh
for i, v := range results{
fmt.Println(i, " - ", v)
}
}
func factorial(n int, ch chan struct{}, results map[int]int){
defer close(ch) // închidem canalul după ce gorutina s-a încheiat
result := 1
for i := 1; i <= n; i++{
result *= i
results[i] = result
}
}
În acest caz, funcția factorial calculează în continuare factorialul, dar plasează toate factorialele numerelor de la 1 la n într-o hartă results, unde cheile reprezintă numerele, iar valorile sunt factorialele acestora.
Canalul prin care gorutinele interacționează reprezintă tipul chan struct{}. De asemenea, funcția factorial nu trimite date concrete în canal, ci pur și simplu îl închide după ce își finalizează toate instrucțiunile prin apelul defer close(ch). După închiderea canalului, funcția main primește semnalul corespunzător pe linia <-structCh, iar apoi funcția main își continuă execuția.