Golang 實現輕量、快速的基於 Reactor 模式的非阻塞 TCP 網絡庫

gev 輕量、快速的 Golang 網絡庫

gev 是一個輕量、快速的基於 Reactor 模式的非阻塞 TCP 網絡庫,底層並不使用 golang net 庫,而是使用 epoll 和 kqueue,所以它並不支持 Windows。html

爲何有 gev

Golang 的 goroutine 雖然很是輕量,可是每啓動一個 goroutine 仍須要 4k 左右的內存。讀了鳥窩大佬的文章【百萬 Go TCP 鏈接的思考: epoll方式減小資源佔用】後,便去研究了了下 eviolinux

evio 雖然很是快,可是仍然存在一些問題,便嘗試去優化它,因而有了 eviop 項目。關於 evio 的問題能夠看個人另外一篇博文 【Golang 網絡庫evio一些問題/bug和思考】。在優化 evio 完成 eviop 的過程當中,由於其網絡模型的緣故,越發感受修改它很是麻煩,成本比從新搞一個還高。git

最終決定本身重搞一個,更加輕量,不須要的全去掉。加上大學時學習過 muduo ,便參考 muduo 的使用的 Reactor 模型實現 gev 。github

在 linux 環境下,gev 底層使用 epoll ,這是 gev 會專一優化的地方。在 mac 下底層使用 kqueue,可能不會過多關注這部分的優化,畢竟不多有用 mac 作服務器的(Windows 環境"暫"不支持)。golang

特色

  • 基於 epoll 和 kqueue 實現的高性能事件循環
  • 支持多核多線程
  • 動態擴容 Ring Buffer 實現的讀寫緩衝區
  • 異步讀寫
  • SO_REUSEPORT 端口重用支持

網絡模型

gev 只使用極少的 goroutine, 一個 goroutine 負責監聽客戶端鏈接,其餘 goroutine (work 協程)負責處理已鏈接客戶端的讀寫事件,work 協程數量能夠配置,默認與運行主機 CPU 數量相同。bash

image.png

性能測試

測試環境 Ubuntu18.04服務器

和同類庫的簡單性能比較, 壓測方式與 evio 項目相同。網絡

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

限制 GOMAXPROCS=1,1 個 work 協程多線程

image.png

限制 GOMAXPROCS=1,4 個 work 協程app

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

相關文章

相關文章
相關標籤/搜索