1. 程式人生 > 程式設計 >Golang 實現輕量、快速的基於 Reactor 模式的非阻塞 TCP 網路庫

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 的問題可以看我的另一篇博文 【

Golang 網路庫evio一些問題/bug和思考】。在優化 evio 完成 eviop 的過程中,因為其網路模型的緣故,愈加感覺修改它非常麻煩,成本比重新搞一個還高。

最終決定自己重搞一個,更加輕量,不需要的全去掉。加上大學時學習過 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 數量相同。

image.png

效能測試

測試環境 Ubuntu18.04

和同類庫的簡單效能比較,壓測方式與 evio 專案相同。

  • gnet
  • eviop
  • evio
  • net (標準庫)

限制 GOMAXPROCS=1,1 個 work 協程

image.png

限制 GOMAXPROCS=1,4 個 work 協程

image.png

限制 GOMAXPROCS=4,4 個 work 協程

image.png

安裝

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 實現。

相關文章