2014-07-23 18 views
6

Próbuję zrozumieć, jak działa kanał golang. Przeczytałem książkę o języku go i znalazłem następujący przykład.Dlaczego zdarza się tutaj impas?

package main 

import (
    "fmt" 
) 

// Send the sequence 2, 3, 4, ... to returned channel 
func generate() chan int { 
    ch := make(chan int) 
    go func() { 
     for i := 2; i <= 100 ; i++ { 
      ch <- i 
     } 
    }() 
    return ch 
} 

// Filter out input values divisible by 'prime', send rest to returned channel 
func filter(in chan int, prime int) chan int { 
    out := make(chan int) 
    go func() { 
     for { 
      if i := <-in; i%prime != 0 { 
       out <- i 
      } 
     } 
    }() 
    return out 
} 

func sieve() chan int { 
    out := make(chan int) 
    go func() { 
     ch := generate() 
     for { 
      prime := <-ch 
      ch = filter(ch, prime) 
      out <- prime 
     } 
    }() 
    return out 
} 

func main() { 
    primes := sieve() 
    for { 
     fmt.Println(<-primes) 
    } 
} 

Gdy ten programm, mam impasu, ale kiedy zmienić funkcję generowania do

// Send the sequence 2, 3, 4, ... to returned channel 
func generate() chan int { 
    ch := make(chan int) 
    go func() { 
     for i := 2; ; i++ { 
      ch <- i 
     } 
    }() 
    return ch 
} 

Następnie programowe uruchomi nieskończoną pętlę, ale nie impasu. Dlaczego dostaję zakleszczenie, kiedy usunę warunek w pętli for?

Odpowiedz

9

Co masz na myśli z zasadą blokowania?

Widać to pokazano na blogu "The Nature Of Channels In Go"

o wydanie niebuforowanym channel:

http://3.bp.blogspot.com/-vnJIWvlbP-E/UwDVICJKB9I/AAAAAAAANX0/T04V_58i8Vs/s1600/Screen+Shot+2014-02-16+at+10.10.54+AM.png

(Ilustracja z blogu "The Nature Of Channels In Go", napisany przez William Kennedy, luty 2014)

Kanały niebuforowane nie mają pojemności, a zatem wymagają, aby oba gorutyny były gotowe do wykonania dowolnej wymiany.
Kiedy goroutine próbuje napisać zasób do niebuforowanym kanału i nie ma goroutine czeka na odebranie zasób, kanał będzie zablokować goroutine i zrobić to czekać.
Kiedy goroutine próbuje odczytać z niebuforowanym kanału, a nie ma goroutine czeka wysłać do zasobu, kanał będzie zablokować goroutine i sprawiają, że czekać.

To, co dzieje się w twoim przypadku z czytnika:

func main() { 
    primes := sieve() 
    for { 
     fmt.Println(<-primes) 
    } 
} 

od primes nigdy nie jest zamknięta, main pozostaje zablokowana.
It (main) jest w punkcie 3:

w kroku 3, goroutine po prawej kładzie rękę do kanału lub wykonuje czytać.
To goroutine jest również zamknięty w kanale, aż wymiana jest zakończona.

Nadawca nigdy nie dzwoni pod numer close(primes).

+0

Mam zakleszczenie, ponieważ goroutine w funkcji generowania jest kanał jest blisko po 100 pętli i prime nadal czekać na otrzymanie danych w prawo? –

+0

@ zero_coding nie jest zamknięty: nie widzę 'close (liczb pierwszych)' w dowolnym miejscu – VonC

+0

Mam na myśli, ponieważ odbiornik nie zamyka się, ale nadawca jest blisko, prawda? Nigdy więcej nadawcy. –

5

Rozważmy prostszy przykład:

func generate() chan int { 
    ch := make(chan int) 
    go func() { 
     for i := 2; /*i < 100*/; i++ { 
      ch <- i 
     } 
    }() 
    return ch 
} 

func main() { 
    for i := range generate() { 
     fmt.Println(i) 
    } 
} 

ze stanem i < 100 komentarzem, w goroutine wywoływanych przez generate przystanków po wysłaniu 98 liczb. Nie zamyka jednak kanału, więc nie ma możliwości dowiedzenia się, że nie ma już żadnych numerów, i po prostu blokuje kanał. Od main jest obecnie jedynym istniejącym goroutinem (ten drugi powrócił), a on blokuje, masz impas.

+0

Czytałem również temat blokowania kanałów, ale nie rozumiem, co to znaczy z kanałem blokującym. Kanał składa się z nadawcy i odbiorcy. Nadawca może wysłać coś tylko na raz, co oznacza, że ​​odbiorca musi odebrać paczkę, dopóki nie będzie kontynuował swojej pracy. Co masz na myśli mówiąc o zasadzie blokowania? –

Powiązane problemy