golang快速入门-02
goroutine的并发数量
不控制并发的 goroutine 数量会发生什么?
CPU 使用率浮动上涨
Memory 占用不断上涨
主进程崩溃(被杀掉了)原因是打开文件数量太多内存占用等对系统资源占用过大
解决方案
控制/限制 goroutine 同时并发运行的数量
改变应用程序的逻辑写法(避免大规模的使用系统资源和等待)
使用chan和sync
实现了控制 goroutine 以 2 个 2 个的数量去执行我们的 “业务逻辑”
var wg = sync.WaitGroup{}
func main() {
userCount := 10
ch := make(chan bool, 2)
for i := 0; i < userCount; i++ {
wg.Add(1)
go Read(ch, i)
}
wg.Wait()
}
func Read(ch chan bool, i int) {
defer wg.Done()
ch <- true
fmt.Printf("go func: %d, time: %d\n", i, time.Now().Unix())
time.Sleep(time.Second)
<-ch
}
循环交互赋值是性能分析
常常会遇到循环交换赋值的数据处理场景,尤其是 RPC,数据交互格式要转为 Protobuf,赋值是无法避免的。
一般会有如下几种做法:
for
for range
json.Marshal/Unmarshal
三种做法的性能顺序为1 > 2 > 3
for range 在性能上相较 for 差 json。Marsha1最差
for range 始终使用值拷贝的方式来生成循环变量。通俗来讲,就是在每次循环时,都会对循环变量重新分配.
encoding/json 标准库,是通过大量反射来实现的, 因此很慢
总结
对性能开销有较高要求:选用 for,开销最小
中规中矩:选用 for range,大对象慎用
量小、占用小、数量可控:选用 json.Marshal/Unmarshal 的方案也可以。其重复代码少,但开销最大
为什么 Go map 遍历输出是不固定顺序?
for range map 在开始处理循环逻辑的时候,就做了随机播种.根据随机数,选择一个桶位置作为起始点进行遍历迭代.
评论