2015-07-21 41 views
6

Niepubliczne kanały blokują odbiorniki, dopóki dane nie będą dostępne na kanale. Nie jest dla mnie jasne, jak to blokowanie zachowuje się z wieloma odbiornikami na tym samym kanale (np. Przy korzystaniu z goroutinów). Jestem pewien, że wszyscy będą blokować tak długo, jak długo nie będą wysyłane dane na ten kanał.
Ale co się stanie, gdy wyślę pojedynczą wartość do tego kanału? Który odbiornik/goroutine otrzyma dane, a zatem odblokuje? Wszyscy? Pierwszy w kolejce? Losowy?Wiele odbiorników na jednym kanale. Kto otrzymuje dane?

Odpowiedz

12

Otrzyma je pojedynczy losowy (niedeterministyczny).

+0

stan Race? Czy można to zrobić bezpiecznie? –

+0

Tak, to po prostu gorsze, że goroutine dostaje żywioł. – inf

+4

Nie nazwałbym tego "stanem wyścigu". Termin ten jest tradycyjnie definiowany, aby wskazać niezamierzone zachowanie z powodu niebezpiecznego współbieżnego dostępu do zmiennej. Kanały są zaprojektowane tak, aby były bezpiecznie dostępne jednocześnie i nie ma nic złego w wielu czytnikach na niebuforowanym kanale. – JimB

4

Domyślnie komunikacja z goroutine to synchronous i unbuffered: wysyłanie nie jest zakończone do momentu, aż odbiornik zaakceptuje wartość. Musi być odbiornik gotowy do odbioru danych z kanału, a następnie nadawca może przekazać go bezpośrednio do odbiornika.

Więc kanał wysyłania/odbierania operacje blokowania aż druga strona jest gotowa:

1. Operacja wyślij na ciągu bloków kanałowych aż odbiornik jest dostępna dla tego samego kanału: jeśli nie ma odbiorca dla wartości na ch, żadna inna wartość nie może zostać umieszczona w kanale. I na odwrót: żadna nowa wartość nie może zostać wysłana w ch, gdy kanał nie jest pusty! Tak więc operacja wysyłania będzie czekać, aż ch stanie się ponownie dostępna.

2. Operacja odbierania dla bloków kanałów, dopóki nadawca nie jest dostępny dla tego samego kanału: jeśli nie ma wartości w kanale, odbiornik blokuje się.

Ilustruje to poniższy przykład:

package main 
import "fmt" 

func main() { 
    ch1 := make(chan int) 
    go pump(ch1) // pump hangs 
    fmt.Println(<-ch1) // prints only 0 
} 

func pump(ch chan int) { 
    for i:= 0; ; i++ { 
     ch <- i 
    } 
} 

Ponieważ nie ma odbiornik zawiesza goroutine i drukować tylko pierwszy numer.

Aby to obejść, musimy zdefiniować nową goroutine, która czyta z kanału w nieskończonej pętli.

func receive(ch chan int) { 
    for { 
     fmt.Println(<- ch) 
    } 
} 

Następnie w main():

func main() { 
    ch := make(chan int) 
    go pump(ch) 
    receive(ch) 
}