golang其實也可以優先調度


 

線上一個服務有個嚴重問題,處理消息數1k/s提升不上去,經過查看是阻塞在了一個新加的函數上,這個函數負責收集信息,送到一個channel上,再由某個函數處理,這個處理函數很簡單,看不出任何問題,最大的特點是為了不加鎖,只起一個goroutine。

問題很明顯了,只起一個goroutine,當系統繁忙和存在大量goroutine的時候,會得不到調度,無法處理收集到的數據,然后channel緩沖滿,導致收集函數阻塞在發送數據到channel上,進而阻塞了消息處理。

該獲得調度的沒有被調度,不該獲得調度的卻獲得調度了,而go runtime不可能知道那個goroutine應該被調度,只能是公平調度,但是公平調度卻造成了堵塞!

這種問題其實很普遍,不是一個goroutine的問題!就算你開了多個goroutine,仍然可能得不到調度!(當然,是在繁忙的時候,大部分時候不存在這種問題)

當然,這個問題可以用全局隊列來解決,不使用channel,也就不存在阻塞的問題,有些優秀的庫就是這樣提升吞吐的。但是仍然會有偶爾延遲的情況,因此最后還是要解決,調度的問題!

這篇文章《記一次latency問題排查:談Go的公平調度的缺陷》也談到go這個問題,並認為問題無解。

其實我們可以試試,golang提供的一個更簡單的方法,runtime.LockOSThread()。

官方介紹:

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得到獲得更多時間。

下面的test,顯示了runtime.LockOSThread()的確能影響調度,注釋掉runtime.LockOSThread(),有2-60倍的時間差。

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 {}
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM