golang其实也能够优先调度

 

线上一个服务有个严重问题,处理消息数1k/s提高不上去,通过查看是阻塞在了一个新加的函数上,这个函数负责收集信息,送到一个channel上,再由某个函数处理,这个处理函数很简单,看不出任何问题,最大的特色是为了避免加锁,只起一个goroutine。golang

问题很明显了,只起一个goroutine,当系统繁忙和存在大量goroutine的时候,会得不到调度,没法处理收集到的数据,而后channel缓冲满,致使收集函数阻塞在发送数据到channel上,进而阻塞了消息处理。函数

该得到调度的没有被调度,不应得到调度的却得到调度了,而go runtime不可能知道那个goroutine应该被调度,只能是公平调度,可是公平调度却形成了堵塞!spa

这种问题其实很广泛,不是一个goroutine的问题!就算你开了多个goroutine,仍然可能得不到调度!(固然,是在繁忙的时候,大部分时候不存在这种问题)线程

固然,这个问题能够用全局队列来解决,不使用channel,也就不存在阻塞的问题,有些优秀的库就是这样提高吞吐的。可是仍然会有偶尔延迟的状况,所以最后仍是要解决,调度的问题!设计

这篇文章《记一次latency问题排查:谈Go的公平调度的缺陷》也谈到go这个问题,并认为问题无解。code

其实咱们能够试试,golang提供的一个更简单的方法,runtime.LockOSThread()。blog

官方介绍:队列

LockOSThread wires the calling goroutine to its current operating system thread. Until the calling goroutine exits or calls UnlockOSThread, it will always execute in that thread, and no other goroutine can.

重点在于no other goroutine can,LockOSThread原本是设计给opengl等东西用的,可是从官方这个说明来看,咱们能够利用它作优先调度,将某个goroutine锁定到某个系统线程,这个线程只调度这个goroutine,进而能够被优先调度(相对其余goroutine)。由于系统线程是根据时间片调度的,所以能让这个goroutine获得得到更多时间。it

下面的test,显示了runtime.LockOSThread()的确能影响调度,注释掉runtime.LockOSThread(),有2-60倍的时间差。class

package main

import (
    "fmt"
    "os"
    "runtime"
    "time"
)

func main() {

    var ch = make(chan bool, 20000)
    var begin = make(chan bool)

    go func() {
        runtime.LockOSThread()
        <-begin
        fmt.Println("begin")
        tm := time.Now()
        for i := 0; i < 10000000; i++ {
            <-ch
        }
        fmt.Println(time.Now().Sub(tm))
        os.Exit(0)
    }()

    for i := 0; i < 50000; i++ {
        // 负载
        go func() {
            var count int
            load := 100000
            for {
                count++
                if count >= load {
                    count = 0
                    runtime.Gosched()
                }
            }
        }()
    }

    for i := 0; i < 20; i++ {
        go func() {
            for {
                ch <- true
            }
        }()
    }

    fmt.Println("all start")
    begin <- true

    select {}
}
相关文章
相关标签/搜索