2016-01-15 5 views
1

Ниже приведен пример кода в книге программирования Go. Я не понимаю, почему ближе должна быть его собственная горутин. Я попытался переместить ближе к, но он сработает. Кто-то может объяснить, почему ближе нужно быть в отдельной горутине?Sync.WaitGroup, почему ближе в goroutine

Спасибо!

func makeThumbnails(filenames <-chan string, result chan<- int64) int64 { 
    sizes := make(chan int64) 
    var wg sync.WaitGroup 
    for f := range filenames { 
     wg.Add(1) 
     go func(f string) { 
     defer wg.Done() 
     sizes <- int64(len(f)) 
     }(f) 
    } 

    // **closer**, why this guy needs to be in a goroutine??? 
    go func() { 
    wg.Wait() 
    close(sizes) 
    }() 

    var total int64 
    for size := range sizes { 
    total += size 
    } 
    result <- total 
    return total 
} 

ответ

3

Проблема заключается в том, что sizes не буферный chan, так что только один из анонимных goroutines могут фактически завершено до sizes потребности следует читать. Это заставляет wg.Wait() ждать навсегда (так как следующий горутин блокируется на sizes <- и не может defer wg.Done()) и тупиков.

Отбрасывая ближе в отдельную горутун, он может закрыть chan, когда он готов сделать это, и обработать от sizes между ними. В конечном итоге это отличное использование горутин - огонь и забудьте закрыть!

Чтобы этот код работал без более близкого goroutine, вы можете просто инициализировать sizes в качестве буферизованного chan с буфером> = длиной filenames.

func makeThumbnails(filenames <-chan string, result chan<- int64) int64 { 
    sizes := make(chan int64, 10) // buffered channel, now! 
    // if filenames sends more than 10 strings, though, we're in trouble!! 

    var wg sync.WaitGroup 
    for f := range filenames { 
     wg.Add(1) 
     go func(f string) { 
      defer wg.Done() 
      sizes <- int64(len(f)) 
     }(f) 
    } 

    // **closer**, this guy doesn't need to be a goroutine!! 
    wg.Wait() 
    close(sizes) 

    var total int64 
    for size := range sizes { 
     total += size 
    } 
    result <- total 
    return total 
} 

Однако поскольку длина filenames «s непознаваем во время выполнения, это не возможно сделать это легко. Вам нужно будет прочитать filenames, сохранить его в кусочек, затем инициализировать размеры и for над range filenamesSlice и ... да, в основном вы только что переписали всю функцию в этот момент.

+0

Спасибо, получилось :) – WhatABeautifulWorld