Golang 實現輕量、快速的基於 Reactor 模式的非阻塞 TCP 網路庫
gev 輕量、快速的 Golang 網路庫
gev 是一個輕量、快速的基於 Reactor 模式的非阻塞 TCP 網路庫,底層並不使用 golang net 庫,而是使用 epoll 和 kqueue,因此它並不支援 Windows。
為什麼有 gev
Golang 的 goroutine 雖然非常輕量,但是每啟動一個 goroutine 仍需要 4k 左右的記憶體。讀了鳥窩大佬的文章【百萬 Go TCP 連線的思考: epoll方式減少資源佔用】後,便去研究了了下 evio。
evio 雖然非常快,但是仍然存在一些問題,便嘗試去優化它,於是有了 eviop 專案。關於 evio 的問題可以看我的另一篇博文 【
最終決定自己重搞一個,更加輕量,不需要的全去掉。加上大學時學習過 muduo ,便參考 muduo 的使用的 Reactor 模型實現 gev 。
在 linux 環境下,gev 底層使用 epoll ,這是 gev 會專注優化的地方。在 mac 下底層使用 kqueue,可能不會過多關注這部分的優化,畢竟很少有用 mac 做伺服器的(Windows 環境"暫"不支援)。
特點
- 基於 epoll 和 kqueue 實現的高效能事件迴圈
- 支援多核多執行緒
- 動態擴容 Ring Buffer 實現的讀寫緩衝區
- 非同步讀寫
- SO_REUSEPORT 埠重用支援
網路模型
gev
只使用極少的 goroutine,一個 goroutine 負責監聽客戶端連線,其他 goroutine (work 協程)負責處理已連線客戶端的讀寫事件,work 協程數量可以配置,預設與執行主機 CPU 數量相同。
效能測試
測試環境 Ubuntu18.04
和同類庫的簡單效能比較,壓測方式與 evio 專案相同。
- gnet
- eviop
- evio
- net (標準庫)
限制 GOMAXPROCS=1,1 個 work 協程
限制 GOMAXPROCS=1,4 個 work 協程
限制 GOMAXPROCS=4,4 個 work 協程
安裝
go get -u github.com/Allenxuxu/gev
複製程式碼
示例
package main
import (
"flag"
"strconv"
"log"
"github.com/Allenxuxu/gev"
"github.com/Allenxuxu/gev/connection"
"github.com/Allenxuxu/ringbuffer"
)
type example struct{}
func (s *example) OnConnect(c *connection.Connection) {
log.Println(" OnConnect : ",c.PeerAddr())
}
func (s *example) OnMessage(c *connection.Connection,buffer *ringbuffer.RingBuffer) (out []byte) {
//log.Println("OnMessage")
first,end := buffer.PeekAll()
out = first
if len(end) > 0 {
out = append(out,end...)
}
buffer.RetrieveAll()
return
}
func (s *example) OnClose() {
log.Println("OnClose")
}
func main() {
handler := new(example)
var port int
var loops int
flag.IntVar(&port,"port",1833,"server port")
flag.IntVar(&loops,"loops",-1,"num loops")
flag.Parse()
s,err := gev.NewServer(handler,gev.Network("tcp"),gev.Address(":"+strconv.Itoa(port)),gev.NumLoops(loops))
if err != nil {
panic(err)
}
s.Start()
}
複製程式碼
參考
本專案受 evio 啟發,參考 muduo 實現。