调度(diao 4 du)
协程池(项目相关)
问题:
不过有个疑问就是。你用的是协程池吗?那我直接,我为每一个需要去处理的分片,我都为这样的一个分片分配一个单独的 goroutine ,不是也可以吗?那为什么要到协程池呢?
回答:
协程池本身具有协程管理能力,在提高任务执行并发度的同时又不会带来协程泛滥导致资源 泄露(应改为耗尽)的问题
问题:
泄露是什么情况?就是说我有一些事情可能需要去并发处理,然后我。为每一件事情都开一个协程,并且它能够正常执行,那这个也叫泄露吗?
回答:
这个也就不叫泄露,但是我主要是考虑到协程池它本身就有这个,协程管理能力,就不我再去额外的就是去做这个维护什么的。
更新:
我应该是把资源耗尽和协程泄露混淆了。所以他会问到,“这个也是泄露吗”
总结:使用协程池还是会有协程泄露的问题
回到这个问题
"那我直接,我为每一个需要去处理的分片,我都为这样的一个分片分配一个单独的 goroutine ,不是也可以吗?那为什么要到协程池呢?"
协程池它在提高任务执行的并发度的同时又不会带来协程泛滥导致资源耗尽的问题,因为协程池本身就有协程管理的能力,可以限制最大并发数,保证服务不会因为流量过大而挂掉。
(当面对突发的大流量,如瞬间 10 万个任务时,虽然 CPU 调度能抗住,但海量协程占用的内存可能会瞬间撑爆机器,导致进程崩溃)
另一个就是复用协程,降低 GC (垃圾回收) 的压力。在高频扫描的场景下,频繁地创建和销毁协程会给 GC 带来巨大的压力
从 map 讲到 sync.map,分段锁
问题:那你觉得决定分段锁 map 的性能?是什么呢?就是如果想要一个分段的map, 它的一个读写性能更好的话,我应该怎么做呢?
回答:分段锁在写多读少的情况下性能表现更好,key分布均匀的场景
补充: 影响分段锁 map 性能的核心因素主要是分段数量,分段数量越多,井发度越高,锁冲突越小。那性能是最好的。但是这个性能提升也是有限的,随着这个分段数量的增多,内存占用也会比较大。我自己做了下性能测试,像分段锁一些开源的库(orcaman),默认分段数量就是32,一般情况下分 32 个段其实也是够的。然后我把分段的数量提升到256,还有1024的时候,它的性能其实就不如sync.map了
*sync.map在go的1.24版本后底层用哈希前缀树结构实现,加节点锁。
GMP模型
问题:全局队列它的作是什么呢?
回答:
全局队列就是它这个 p ,它的本地 goroutine 队列满了之后它就会尝试将新创建的 goroutine 和本地队列的一半的 goroutine 就会放到全局队列中。减少锁竟争,还有共享资源。
问题:这个锁竟争是指哪里的?
投降🏳️
补充:
第一个问题,全局队列的一个作用就是p的本地G队列满了以后,它就将新创建的 goroutine 和本地队列的一半的 goroutine 就会放到全局队列中。或者就是本地队列为空时,尝试从全局队列偷取可运行的G来运行,减少空旋。
第二个问题,全局队列对锁竞争的影响
OMG,我就不应该扯到锁竞争。直接减少锁竞争的是本地队列和work stealing算法(在自己队列拉取和偷别人的都不会加锁),访问全局队列才会加锁。
将全局队列理解成goroutine负载均衡的一个作用。本地队列的大小就是存放256个goroutine,有的p会存放过多goroutine , 有的p就几乎没有G,分配没有那么均匀。