go中,io密集型的应用,比如有很多文件io,磁盘io,网络io,调大GOMAXPROCS,会不会对性能有帮助?为什么?
这是面试中被问到的。实力有限,真正的答案还不知道。
答案1: 调节这个参数影响的是P的个数,也就影响了M(线程)干活的个数。相当于你可以有更多的执行线程。 先以网络io来说,网络io 在golang 里面是异步的,用epoll池做的io复用。每个网络调用其实都是异步的,发数据给到内存,调度权就可以让给其他goroutine了,所以,其实一个线程能处理过来的话,性能是不会差的,这个时候你加多P其实提升不大。只有你单线程处理不过来这些网络io的时候(每个都处理很慢),加多P才有明显提升
如果是磁盘io的话,这个有点特殊,磁盘io不是异步的,没有aio这种方式。所以你的磁盘io调用下去就卡住M了,这个时候等sysmon发现系统调用超时才会抢占M,这一来回就耗费时间了,所以,这种情况下你干活的M多一点确实能带来一些性能的提升,相当于并行干活的M多一些。 无论哪种情况,P的个数都不建议超过本机cpu的个数。因为多个cpu才是真正的并行执行,上层都是通过调度切换模拟出来的。
答案2: GOMAXPROCS 用默认的,就是CPU的硬件线程数目, 对于大部分IO密集的应用是不合适的。 至少应该配置到硬件线程数目的5倍以上, 最大256。 GO的调度器是迟钝的,它很可能什么时都没做,直到M阻塞了想当长时间以后,才会发现有一个P/M被syscall阻塞了。然后,才会用空闲的M来强这个P。 补充说明:调度器迟钝不是M迟钝,M也就是操作系统线程,是非常的敏感的,只要阻塞就会被操作系统调度(除了极少数自旋的情况)。但是GO的调度器会等待一个时间间隔才会行动,这也是为了减少调度器干预的次数。也就是说,如果一个M调用了什么API导致了操作系统线程阻塞了,操作系统立刻会把这个线程M调度走,挂起等阻塞解除。这时候,Go调度器不会马上把这个M持有的P抢走。这就会导致一定的P被浪费了。 这就是为何,GOMAXPROCS 太小,也就是P的数量太少,会导致IO密集(或者syscall较多)的go程序运行缓慢的原因。 那么,GOMAXPROCS 很大,超过硬件线程的8倍,会不会有开销呢? 答案是,开销是有的,但是远小于Go运行时迟钝的调度M来抢夺P而导致CPU利用不足的开销。