最近發現, golang寫的游戲服務器, 在非調試狀態下, 一切正常, 但是在掛接gdb調試時, 無法收到網絡消息. 打了很多日志, 發現, 只要有goroutine的地方, 都沒有切換進入.
回想了下, goroutine的調度規則: 1.4之前, 在碰到syscall時, goroutine會被調度并處理. 1.4后, 只要有函數調用時, 均會進行一次調度. 密度比以前增加了, 更加接近真線程的處理.
根據這個原理, 問題應該出現在服務器底層沒有給系統提供調度機會的點上. 我們的服務器通過一個bool型的chan進行阻塞, 讓服務器維持阻塞進行消息處理不退出. 但是最近為了在windows下提供命令行支持, 增加了一些代碼, 如下
1: func WaitForExit() { 2: 3: if len(peerMap) == 0 {
4: log.Println("no peer running, exit!")
5: return
6: } 7: 8: // 命令行功能只在windows下啟用
9: if runtime.GOOS == "windows" {
10: reader := bufio.NewReader(os.Stdin) 11: 12: var running bool = true
13: 14: go func() { 15: select {16: case <-exitChan:
17: running = false
18: } 19: }() 20: 21: for running {
22: data, _, _ := reader.ReadLine()23: command := string(data)
24: 25: dispatchConsoleCommand(command) 26: }27: } else {
28: // Linux環境
29: <-exitChan 30: } 31: 32: }我暫時屏蔽了新加的這套功能, 維持<-exitChan, 問題馬上解決
結合前面的猜測, 我估計在reader.ReadLine()函數內, 沒有給底層提供調度的機會, 導致其他goroutine無法運行, 造成服務器卡死
技術討論群: 309800774 歡迎golang愛好者加入, 純技術研討


