gev 是一個輕量、快速的基於 Reactor 模式的非阻塞 TCP 網絡庫,底層並不使用 golang net 庫,而是使用 epoll 和 kqueue,所以它並不支持 Windows。html
Golang 的 goroutine 雖然很是輕量,可是每啓動一個 goroutine 仍須要 4k 左右的內存。讀了鳥窩大佬的文章【百萬 Go TCP 鏈接的思考: epoll方式減小資源佔用】後,便去研究了了下 evio。linux
evio 雖然很是快,可是仍然存在一些問題,便嘗試去優化它,因而有了 eviop 項目。關於 evio 的問題能夠看個人另外一篇博文 【Golang 網絡庫evio一些問題/bug和思考】。在優化 evio 完成 eviop 的過程當中,由於其網絡模型的緣故,越發感受修改它很是麻煩,成本比從新搞一個還高。git
最終決定本身重搞一個,更加輕量,不須要的全去掉。加上大學時學習過 muduo ,便參考 muduo 的使用的 Reactor 模型實現 gev 。github
在 linux 環境下,gev 底層使用 epoll ,這是 gev 會專一優化的地方。在 mac 下底層使用 kqueue,可能不會過多關注這部分的優化,畢竟不多有用 mac 作服務器的(Windows 環境"暫"不支持)。golang
gev
只使用極少的 goroutine, 一個 goroutine 負責監聽客戶端鏈接,其餘 goroutine (work 協程)負責處理已鏈接客戶端的讀寫事件,work 協程數量能夠配置,默認與運行主機 CPU 數量相同。bash
測試環境 Ubuntu18.04服務器
和同類庫的簡單性能比較, 壓測方式與 evio 項目相同。網絡
限制 GOMAXPROCS=1,1 個 work 協程多線程
限制 GOMAXPROCS=1,4 個 work 協程app
限制 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 實現。