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 {}
}
相關文章
相關標籤/搜索