2013-08-01 2 views
5

Я пытаюсь понять эту проблему, описанную на этом слайде:Как этот чан просочился?

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

Копирование кода в случае URL умирает:

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") 
} 

И комментарии:

  • goroutine заблокирован на chan write
  • goroutine содержит ссылку на t он чан
  • Чан никогда не будет мусора

Я не уверен, я понимаю, почему чан никогда не будет собираться или который goroutine держит ссылку на чан. Ваше время ценится!

ответ

5

The Go Programming Language Specification

Function literals

Функция буквальным представляет собой анонимную функцию.

FunctionLit = "func" Function . 

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

Функциональный литерал может быть назначен переменной или вызван напрямую.

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

Функциональные литералы замыкания: они могут ссылаться на переменные, определенные в окружения функции. Эти переменные затем распределяются между окружающей средой и литералом функции, и они сохраняются как долго, поскольку они доступны.

Send statements

отправить заявление посылает значение по каналу. Выражение канала должно быть типа канала, направление канала должно разрешать операции , а тип отправляемого значения должен быть назначен тип элемента канала.

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

Оба канала и значение выражения вычисляются до начала связи. Коммуникационные блоки до отправки могут продолжаться. Отправка по небуферизованному каналу может продолжаться, если приемник готов. A отправка по буферному каналу может продолжаться, если в буфере есть место. Посылается по замкнутому каналу, вызывая время выполнения panic. A отправьте по блокам каналов nil навсегда.

Существует только один go заявления, go func(addr string), и это замыкание по переменному каналу 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 
} 

Два goroutines запускаются так len(addrs) == 2.Из-за преждевременного выхода, когда err != nil на первом приеме на канале errc, завершается только один горутин. Второй goroutine блокируется при отправке (записи) на небуферизованный канал errc; он никогда не завершается. Поэтому есть еще ссылка на errc, поэтому он никогда не собирает мусор. Вторая версия gotoutine в конечном счете прекращается, когда программа выходит.

Смежные вопросы