亲和性的局限

要理解亲和性的局限,就得先知道本地队列和全局队列发生了什么。
本地队列会被用于除了系统调用外的如channel,select,timer等待等阻塞操作,
然而,两种情况会限制goroutine和线程的亲和性:goroutine窃取和系统调用。
但是,通过更好地管理本地队列的优先级,可以有效规避上述两种情况。
G1.5旨在给予那些通过channel通讯的goroutine更高优先级,从而优化goroutine
与所在线程的亲和性

如何提高亲和性

协程在channel上来回通讯会导致该协程被频繁地阻塞,例如前所述,频繁入队本地队列。
然而,由于本地队列是FIFO,当某个协程独占线程时,那些非阻塞的协程没法保证能尽快运行,
如下例子:

从channel阻塞释放的协程

协程9在被channel阻塞完毕后恢复正常,然而它必须等待2号,5号和4号协程执行完毕,在本例中,
5号协程会独占协程,导致9号协程被延迟执行并增加了9号协程被其他P偷走的风险。
自从Go 1.5版本开始,从channel返回的协程会被传到P的runnext字段以最高优先级执行。

协程放入到P的runnext

该方式在再次进入channel阻塞前尽快运行一次,然后其他协程才被陆续执行。
这个方式的引入对Go的标准库的整体起到积极作用。
因为本地队列是FIFO的结构,如果队列里有goroutine独占着OS线程,则刚从channel阻塞出来的
goroutine无法保证尽早的执行。

提高一些库的性能

参考

Go: Concurrency & Scheduler Affinity