concurrent.go:
package main
import (
"fmt"
"sync"
)
// JOBS represents the number of jobs workers do
const JOBS = 2
// WORKERS represents the number of workers
const WORKERS = 5
func work(in <-chan int, out chan<- int, wg *sync.WaitGroup) {
for n := range in {
out <- n * n
}
wg.Done()
}
var wg sync.WaitGroup
func main() {
in := make(chan int, JOBS)
out := make(chan int, JOBS)
for w := 1; w <= WORKERS; w++ {
wg.Add(1)
go work(in, out, &wg)
}
for j := 1; j <= JOBS; j++ {
in <- j
}
close(in)
wg.Wait()
close(out)
for r := range out {
fmt.Println("result:", r)
}
// This is a solution but I want to do it with `range out`
// and also without WaitGroups
// for r := 1; r <= JOBS; r++ {
// fmt.Println("result:", <-out)
// }
}
示例是goplay上的here。
答案 0 :(得分:3)
Goroutines同时独立运行。 Spec: Go statements:
“go”语句在同一地址空间内作为独立并发控制线程或 goroutine 开始执行函数调用。
如果您想使用for range
从out
频道接收值,则表示out
频道只有在所有goroutine完成发送后才能关闭。
由于goroutine并发且独立地运行,没有同步,你就不能拥有它。
使用WaitGroup
是一种方法,一种方法(确保我们在关闭out
之前等待所有goroutine完成工作。)
您的注释代码是另一种方式:注释代码从通道接收与Goroutine应该发送的数量完全一样多的值,这只有在所有goroutine都发送它们的值时才有可能。同步是发送语句和接收操作。
备注:强>
通常从通道接收结果是异步完成的,在专用的goroutine中,或者甚至使用多个goroutine。这样做不需要使用具有缓冲能力缓冲所有结果的通道。你仍然需要同步来等待所有工人完成他们的工作,由于gorutine调度和执行的并发和独立性,你无法避免这种情况。
答案 1 :(得分:-1)
这是没有waitgroup
的示例同步证明。
package main
import (
"fmt"
)
// number of jobs workers do
const JOBS = 10
// number of workers
const WORKERS = 2
func work(in <-chan int, out chan<- int, done chan<- bool) {
for n := range in {
out <- n * n
}
done <- true
}
func main() {
in := make(chan int, JOBS)
out := make(chan int, JOBS)
done := make(chan bool, WORKERS)
// launch workers
for w := 1; w <= WORKERS; w++ {
go work(in, out, done)
}
// give jobs to workers
for j := 1; j <= JOBS; j++ {
in <- j
}
close(in)
// list the results
go func() {
i := 0
for r := range out {
fmt.Println("result:", r)
// when all jobs completed mark as done
if i++; i == JOBS {
done <- true
}
}
}()
// wait for all goroutines to keep up
// WORKERS + RESULT go routines
for i := 0; i < WORKERS + 1; i++ {
<- done
}
// prevent leaking chans
close(out)
}