Open geektutu opened 3 years ago
// main_chan.go
func main() {
var wg sync.WaitGroup
ch := make(chan struct{}, 3)
for i := 0; i < 10; i++ {
- ch <- struct{}{}
wg.Add(1)
go func(i int) {
defer wg.Done()
+ ch <- struct{}{}
log.Println(i)
time.Sleep(time.Second)
<-ch
}(i)
}
// 这里我们可以做其他的事情
log.Println("do other thing")
wg.Wait()
}
在其他地方看到控制协程的时候, ch <- struct{}{}
有放在协程内部的。
想了想,作者最终的实现效果是每次只开 3 个协程,想开新协程时会阻塞住整个代码。(PS: 而且代码里面的 wg 每 Add 1, 就 Done 1,实际上最后 Wait 的只有最后 3 个协程)
而将 ch <- struct{}{}
放在协程里面时,会将所有协程创建,但只有前3个可以继续执行,而其他的协程会阻塞住。这种实现的好处在于代码可以继续执行下去。
话说不会是作者笔误写错了吧? :smile:
@kele1997 你的质疑是有道理的,不过 ch <- struct{}{} 放到协程内部的话,子协程还是先创建了,channel 只是阻塞了协程内部的执行,达不到限制协程数量的目的。
所以的话,如果需要不阻塞,后面还能继续干活的话,就可以把整个部分,再包装成一个异步的协程。这样协程数量就是 3+1。
比较常见的,比如 HTTP 服务,先启动一个异步的后台协程用于请求数据库,在这个异步协程里用 channel 接收任务,接收后再启动子协程处理,每个 API 请求进来,通过 channel 告知这个后台协程处理。通过设置 channel 的 buffer 大小,就可以控制后台协程并发创建的子协程的数量。
go pool.Process(i) 这个地方需要用到并发么?是不是去掉go 就行?还有就是,这块是不是得用waitgroup来防止主线程退出?
2^31 次方约为 20 亿哈,不是 2 亿。
@kele1997
// main_chan.go func main() { var wg sync.WaitGroup ch := make(chan struct{}, 3) for i := 0; i < 10; i++ { - ch <- struct{}{} wg.Add(1) go func(i int) { defer wg.Done() + ch <- struct{}{} log.Println(i) time.Sleep(time.Second) <-ch }(i) } // 这里我们可以做其他的事情 log.Println("do other thing") wg.Wait() }
在其他地方看到控制协程的时候,
ch <- struct{}{}
有放在协程内部的。
想了想,作者最终的实现效果是每次只开 3 个协程,想开新协程时会阻塞住整个代码。(PS: 而且代码里面的 wg 每 Add 1, 就 Done 1,实际上最后 Wait 的只有最后 3 个协程)
而将ch <- struct{}{}
放在协程里面时,会将所有协程创建,但只有前3个可以继续执行,而其他的协程会阻塞住。这种实现的好处在于代码可以继续执行下去。话说不会是作者笔误写错了吧? :smile:
<-ch放defer语句中会比较好吧,就算panic了也能够释放struct{}{}
@kele1997 没有错,这里本来就是为了限制携程数量,如果写在里面,那么就是会创建无数个协程序,会消耗系统内存或者其他资源达到资源上限。
这第三方库实现的pool好..别扭啊。1:task是固定的,正常应该支持任意函数;2:对外暴露的提交api不合理,提交的时候为什么在外部使用go pool.procress(foo)。
正常来讲三个方法足够,清晰简单,调用方没那么多心智负担: 1,new(routineSize int,queueSieze int)创建方法指定两个size 2,submit(task taskType),提交后就放到任务对立里直接返回 3,shutdown(),不再接收新任务,等待队列任务执行完成后关闭
关于 第三方 goroutine pool. https://github.com/Jeffail/tunny 这个 好像几年没 更新了. https://github.com/alitto/pond 这个 比较新, 但是 貌似 挺好用.
https://geektutu.com/post/hpg-concurrency-control.html
Go 语言/golang 高性能编程,Go 语言进阶教程,Go 语言高性能编程(high performance go)。本文介绍了 goroutine 协程并发控制,避免并发过高,大量消耗系统资源,导致程序崩溃或卡顿,影响性能。主要通过 2 种方式控制,一是使用 channel 的缓冲区,二是使用第三方协程池,例如 tunny 和 ants。同时介绍了使用 ulimit 和虚拟内存(virtual memory)提高资源上限的技巧。