Go协程
协程对性能的提升:
程序性能由三者决定: 计算时长, 磁盘IO, 网络IO
协程能有效解决IO问题.
对于计算密集型程序则用处较小.
1. 最佳协程使用实践
// 子协程
func CoroutineSubFunc(wg *sync.WaitGroup, resultChannel chan int, limiter chan bool) {
defer wg.Done()
result := time.Now().Minute()
result += 10000
resultChannel <- result // 单个结果
<-limiter
}
// 主协程
func CoroutineMainFunc() {
var wg = &sync.WaitGroup{}
var limiter = make(chan bool, 10) // 限制器,10个协程
var resultSlice []int // 结果列表
var resultChannel = make(chan int, 100)
defer close(limiter)
go func() {
for response := range resultChannel {
resultSlice = append(resultSlice, response)
}
}()
for i := 0; i < 10000000; i++ {
wg.Add(1)
limiter <- true
go CoroutineSubFunc(wg, resultChannel, limiter)
}
wg.Wait()
close(resultChannel)
}
2. 协程限制器的必要性(双channel)
网络IO
//limiter <- true
// 是否单独添加限制器的影响
//before:
//Update耗时-Git仓库信息-获取项目人员:1.8998607s
//Update耗时-Git仓库信息-获取项目人员:1.7111329s
//Update耗时-Git仓库信息-获取项目人员:1.7577459s
//Update耗时-Git仓库信息-获取项目人员:1.7185806s
//Update耗时-Git仓库信息-获取项目人员:1.796424s
// after:
//Update耗时-Git仓库信息-获取项目人员:1.9105957s
//Update耗时-Git仓库信息-获取项目人员:2.0276002s
//Update耗时-Git仓库信息-获取项目人员:1.8378465s
//Update耗时-Git仓库信息-获取项目人员:1.9639478s
//Update耗时-Git仓库信息-获取项目人员:1.9181765s
计算密集型
// 10mlion, 是否单独添加限制器的影响
//before:
//耗时:17.7392589s
耗时:10.6744323s
耗时:12.0589872s
耗时:10.6573216s
耗时:13.3833896s
耗时:10.2832911s
// after:
//耗时:4.862482s
耗时:4.8140741s
耗时:4.9224885s
耗时:4.8152887s
耗时:4.8263113s
耗时:4.8267736s
高并发场景为什么需要限制器?
协程本身切换是需要保存上下文的, 尽管保存每个协程的开销并不大. 但如果有极高并发的情况下, 没有对应的协程限制器, 从而无限制的制造新的协程, 反而会因为内存占用过多, 导致程序运行缓慢. 严重时会导致程序卡死.
增加协程限制器, 能避免RAM无限制增涨, 以提升效率.
3. 双等待池的处理方式(双WaitGroup)
双等待池的处理方式, 一般是在处理针对协程函数有返回数据的时候.
使用第二的等待池来对chan进行读取.
计算密集: 10milion数据
// 单Group
耗时:4.8263338s
耗时:4.8079532s
耗时:4.8333302s
耗时:4.8605043s
耗时:4.8274169s
// 双Group
耗时:4.8698299s
耗时:4.9381441s
耗时:4.8381543s
耗时:4.9011613s
耗时:4.9681705s
网络IO密集: 1000数据
// 单Group
Update耗时: 2.7795841s
Update耗时: 2.7134584s
Update耗时: 2.9046917s
Update耗时: 2.8001659s
Update耗时: 2.7793065s
// 双Group
Update耗时 :2.9160356s
Update耗时 :2.808227s
Update耗时 :2.7915349s
Update耗时 :2.8187473s
Update耗时 :2.7912972s
综上所述:
因为已经有同一个channel, 对其进行限制.
所以双WaitGroup对于协程取值来讲, 并无必要性.
反而会因为对应的开销, 导致性能相对较慢.
必要性: 保证数据完整性.
性能影响: 增加开销, 性能略微下降