2013-08-01 9 views
5

sto cercando di capire il problema descritto in questa diapositiva:Come è trapelato questo chan?

http://talks.golang.org/2013/bestpractices.slide#27

Copiare il codice nel caso in cui l'URL muore:

func sendMsg(msg, addr string) error { 
    conn, err := net.Dial("tcp", addr) 
    if err != nil { 
     return err 
    } 
    defer conn.Close() 
    _, err = fmt.Fprint(conn, msg) 
    return err 
} 

func broadcastMsg(msg string, addrs []string) error { 
    errc := make(chan error) 
    for _, addr := range addrs { 
     go func(addr string) { 
      errc <- sendMsg(msg, addr) 
      fmt.Println("done") 
     }(addr) 
    } 

    for _ = range addrs { 
     if err := <-errc; err != nil { 
      return err 
     } 
    } 
    return nil 
} 

func main() { 
    addr := []string{"localhost:8080", "http://google.com"} 
    err := broadcastMsg("hi", addr) 

    time.Sleep(time.Second) 

    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    fmt.Println("everything went fine") 
} 

E i commenti:

  • la goroutine è bloccata sul chan write
  • la goroutine contiene un riferimento a t egli chan
  • il chan sarà mai garbage collection

io non sono sicuro di aver capito il motivo per cui il chan non viene mai raccolti o che goroutine è mantenere un riferimento al chan. Il tuo tempo è apprezzato!

risposta

5

The Go Programming Language Specification

Function literals

Una funzione letterale rappresenta una funzione anonima.

FunctionLit = "func" Function . 

func(a, b int, z float64) bool { return a*b < int(z) } 

Una funzione letterale può essere assegnata a una variabile o invocata direttamente.

f := func(x, y int) int { return x + y } 
func(ch chan int) { ch <- ACK }(replyChan) 

letterali di funzione sono chiusure: possono fare riferimento a variabili definite in una funzione circostante. Tali variabili vengono quindi condivise tra la funzione circostante e la funzione letterale, e sopravvivono come finché sono accessibili.

Send statements

Una dichiarazione di invio invia un valore su un canale. L'espressione del canale deve essere di tipo canale, la direzione del canale deve consentire l'invio delle operazioni e il tipo del valore da inviare deve essere assegnabile a il tipo di elemento del canale.

SendStmt = Channel "<-" Expression . 
Channel = Expression . 

Sia il canale e il valore di espressione vengono valutati prima dell'inizio comunicazione. Blocchi di comunicazione fino a quando l'invio può procedere. Un invio su un canale senza buffer può procedere se un ricevitore è pronto. Un send su un canale bufferizzato può procedere se c'è spazio nel buffer. Un'invio su un canale chiuso procede causando un tempo di esecuzione panic. Un invia per sempre ai blocchi di canale nil.

C'è solo un go dichiarazione, go func(addr string), ed è una chiusura sopra la variabile del canale errc.

func broadcastMsg(msg string, addrs []string) error { 
    errc := make(chan error) 
    for _, addr := range addrs { 
     go func(addr string) { 
      errc <- sendMsg(msg, addr) 
      fmt.Println("done") 
     }(addr) 
    } 

    for _ = range addrs { 
     if err := <-errc; err != nil { 
      return err 
     } 
    } 
    return nil 
} 

Due goroutines vengono avviati dal len(addrs) == 2.A causa di un'uscita prematura quando err != nil alla prima ricezione sul canale errc, viene completata una sola goroutine. La seconda goroutine è bloccata sull'invio (scrittura) al canale non bufferizzato errc; non finisce mai. Pertanto, c'è ancora un riferimento a errc, quindi non è mai garbage collection. La seconda goroutine viene infine abbandonata quando il programma termina.

Problemi correlati