chai2010/advanced-go-programming-book

1.5.6 中控制并发执行的Goroutine的最大数目代码示例是否有误

JabinGP opened this issue · 2 comments

提示:1.5.6 基于Channel的通信 中控制并发执行的Goroutine的最大数目代码示例

书中原文

我们可以根据控制Channel的缓存大小来控制并发执行的Goroutine的最大数目, 例如:

var limit = make(chan int, 3)

func main() {
    for _, w := range work {
        go func() {
            limit <- 1
            w()
            <-limit
        }()
    }
    select{}
}

疑惑

代码中没有给出work变量的定义,我个人猜测为函数数组,如下

var work = []func(){
	func() { log.Println("1"); time.Sleep(1 * time.Second) },
	func() { log.Println("2"); time.Sleep(1 * time.Second) },
	func() { log.Println("3"); time.Sleep(1 * time.Second) },
	func() { log.Println("4"); time.Sleep(1 * time.Second) },
	func() { log.Println("5"); time.Sleep(1 * time.Second) },
	func() { log.Println("6"); time.Sleep(1 * time.Second) },
	func() { log.Println("7"); time.Sleep(1 * time.Second) },
	func() { log.Println("8"); time.Sleep(1 * time.Second) },
}

如果work为函数数组,Goroutine在main中的创建并不是同步的,匿名函数中是否应该需要考虑w为闭包引用变量的问题?如定义一个同名局部变量覆盖w来复制一份w的值。

var limit = make(chan int, 3)
var work = []func(){
	func() { log.Println("1"); time.Sleep(1 * time.Second) },
	func() { log.Println("2"); time.Sleep(1 * time.Second) },
	func() { log.Println("3"); time.Sleep(1 * time.Second) },
	func() { log.Println("4"); time.Sleep(1 * time.Second) },
	func() { log.Println("5"); time.Sleep(1 * time.Second) },
	func() { log.Println("6"); time.Sleep(1 * time.Second) },
	func() { log.Println("7"); time.Sleep(1 * time.Second) },
	func() { log.Println("8"); time.Sleep(1 * time.Second) },
}

func main() {
    for _, w := range work {
        w := w
        go func() {
            limit <- 1
            w()
            <-limit
        }()
    }
    select{}
}

你已经不需要看书了,欢迎提交PR

关于这段示例我有个疑问:
在for循环中不是一下开启len(work)个协程吗?只是因为limit的限制,只能保证同时只能有3个协程执行任务,其余协程阻塞吗?