【原創】請避免GO語言中的攜程空跑(CPU忽然激增)

其實GO語言從1.6版本開始很是不錯了,GC性能優化很是到位,而且各類並行設計比重新實現一套C++版本的確是方便很多。web

語言包也不少,庫也相對穩定,徹底能夠適用於生產環境。性能優化

 

本文主要是給剛剛入門新手注意一個攜程空跑的問題,由於這種問題可能在C++中也遇到過,只是一些代碼書寫習慣致使。服務器

 

首先來看一段代碼:socket

func (c *WSConn) processHandler() {
	for {
		select {
		case message, ok := <-c.processMsg: // 處理數據包
			if !ok {
				break
			}
			Call(message.MsgHead.Id, c, message.MsgContext, int(message.MsgHead.Msglen))
		}
	}
}

以上代碼是用於處理一個WEBSOCKET的二進制消息後轉換爲指定處理信息的行爲。函數

可是有沒有同窗發現有什麼問題?可是這段代碼的確有問題,由於當鏈接銷燬後會致使processHandler這個攜程空跑,CPU徹底佔滿,當你有多個鏈接出現這種問題後整臺服務器就會爆掉。性能

首先processMsg是一個channel,這裏若是鏈接關閉了會同時關閉掉這個channel,首先咱們知道select自己會等待channel,這樣是不會消耗CPU的,就像C中的select函數同樣,自己是不消耗的(使用不當的略過)。優化

可是當channel關閉後,整個攜程本因直接銷燬,可是代碼中的break致使select無限循環跑,程序出現空跑現象,這裏的break是相對於select而言的,因此看上去沒毛病可跑起來毛病很大。debug

因此若是當出現空跑或GO語言某個攜程CPU激增,能夠去查看是否是哪一個channel和select在無限循環。設計

因此正確的代碼是:server

func (c *WSConn) processHandler() {
	for {
		select {
		case message, ok := <-c.processMsg: // 處理數據包
			if !ok {
				return // 這裏必須強制結束攜程
			}
			Call(message.MsgHead.Id, c, message.MsgContext, int(message.MsgHead.Msglen))
		}
	}
}

個人排錯方法是使用http的一種性能分析方式

下面是詳細代碼:

main.go

package main

import (
	"log"
	"runtime"

	"net/http" // http包引入
	_ "net/http/pprof" // 性能分析包引入

)

func main() {
	// 設置並行運行
	runtime.GOMAXPROCS(2)

	logger.SetLogName("testserver.log")

    
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}() // 此處創建http專用的性能分析端口

	webSock := knlWebsocket.Create(":88", "null")
	webSock.Listen()

}

  以上代碼僅供拋磚引玉,沒法經過編譯,注意註釋內的代碼。

看代碼很簡單,import 2個包:

import (
	"net/http" // http包引入
	_ "net/http/pprof" // 性能分析包引入

)
而後main函數中加入代碼:
go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}() // 此處創建http專用的性能分析端口

 我在這裏加入了一個攜程來作性能分析,是由於我自己有本身的主處理邏輯,因此必須使用攜程。

   完成以上代碼添加後,直接編譯啓動程序,訪問地址:http://localhost:6060/debug/pprof/,而後就能夠進行愉快的性能分析了

相關文章
相關標籤/搜索