Pracuję nad ćwiczeniem używania kanałów do implementacji kolejki. W szczególności próbuję użyć rozmiaru kanału, aby ograniczyć liczbę równoczesnych goroutinów. Mianowicie, napisałem poniższy kod:Potrzebujesz pomocy w zrozumieniu, dlaczego opcja {} nie blokuje na zawsze
package main
import "fmt"
import "time"
import "math/rand"
func runTask (t string, ch *chan bool) {
start := time.Now()
fmt.Println("starting task", t)
time.Sleep(time.Millisecond * time.Duration(rand.Int31n(1500))) // fake processing time
fmt.Println("done running task", t, "in", time.Since(start))
<- *ch
}
func main() {
numWorkers := 3
files := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"}
activeWorkers := make(chan bool, numWorkers)
for _, f := range files {
activeWorkers <- true
fmt.Printf("activeWorkers is %d long.\n", len(activeWorkers))
go runTask(f, &activeWorkers)
}
select{}
}
Teraz kod wywala się z:
throw: all goroutines are asleep - deadlock!
Moje oczekiwanie było, że wezwanie do wyboru będzie blokować zawsze i niech goroutines zakończyć bez impas.
Mam więc dwojakie pytanie: dlaczego nie blokuje się wyboru na zawsze i nie rzuca się w czasie. Funkcja spoczynku() po pętli for, w jaki sposób mogę uniknąć zakleszczeń?
Cheers,
-mtw
Byłbym ostrożny z tym; wszystko w ruchu jest przekazywane wartością. Mapy i plasterki są rzeczywiście kopiowane, jednak część skopiowanych danych zawiera wskaźniki do danych podstawowych. http://golang.org/doc/faq#pass_by_value. To subtelne, ale ważne rozróżnienie; plasterki mają inne dane, które nie są wskaźnikami i nie są udostępniane. – Greg
@Greg: "Mapy i plasterki są rzeczywiście kopiowane". Rozłupując włosy, tak myślę. Na podstawie połączonej dokumentacji: "Wartości mapy i wycinka zachowują się jak wskaźniki ... Kopiowanie wartości mapy lub wycinka nie powoduje skopiowania danych, na które wskazuje." Moja terminologia nie jest zgodna z tym, czego używają doktorzy Go, ale semantyka jest w dużej mierze równoważna. – Ashe
@Greg: Czyściłem tam trochę prozę. – Ashe