https://taohuawu.club/go-even...linux
https://github.com/panjf2000/...git
歡迎你們圍觀~~,目前還在持續更新,感興趣的話能夠 star 一下暗中觀察哦。github
gnet
是一個基於 Event-Loop 事件驅動的高性能和輕量級網絡庫。這個庫直接使用 epoll 和 kqueue 系統調用而非標準 Golang 網絡包:net 來構建網絡應用,它的工做原理相似兩個開源的網絡庫:libuv 和 libevent。golang
這個項目存在的價值是提供一個在網絡包處理方面能和 Redis、Haproxy 這兩個項目具備相近性能的Go 語言網絡服務器框架。redis
gnet
的亮點在於它是一個高性能、輕量級、非阻塞的純 Go 實現的傳輸層(TCP/UDP/Unix-Socket)網絡庫,開發者可使用 gnet
來實現本身的應用層網絡協議,從而構建出本身的應用層網絡應用:好比在 gnet
上實現 HTTP 協議就能夠建立出一個 HTTP 服務器 或者 Web 開發框架,實現 Redis 協議就能夠建立出本身的 Redis 服務器等等。算法
gnet
衍生自另外一個項目:evio
,可是性能更好。shell
gnet
從新設計開發了一個新內置的多線程模型:『主從 Reactor 多線程』,這也是 netty
默認的線程模型,下面是這個模型的原理圖:緩存
它的運行流程以下面的時序圖:服務器
如今我正在 gnet
裏開發一個新的多線程模型:『帶線程/go程池的主從 Reactors 多線程』,而且很快就能完成,這個模型的架構圖以下所示:網絡
它的運行流程以下面的時序圖:
gnet
的『主從 Reactors 多線程』模型是基於 Golang 裏的 Goroutines的,一個 Reactor 掛載在一個 Goroutine 上,因此在 gnet
的這個網絡模型裏主 Reactor/Goroutine 與從 Reactors/Goroutines 有海量通訊的需求,所以 gnet
裏必需要有一個能在 Goroutines 之間進行高效率的通訊的機制,我沒有選擇 Golang 裏的主流方案:基於 Channel 的 CSP 模型,而是選擇了性能更好、基於 Ring-Buffer 的 Disruptor 方案。
因此我最終選擇了 go-disruptor:高性能消息分發隊列 LMAX Disruptor 的 Golang 實現。
gnet
利用 Ring-Buffer 來緩存 TCP 流數據以及管理內存使用。
$ go get -u github.com/panjf2000/gnet
// ======================== Echo Server implemented with gnet =========================== package main import ( "flag" "fmt" "log" "strings" "github.com/panjf2000/gnet" "github.com/panjf2000/gnet/ringbuffer" ) func main() { var port int var loops int var udp bool var trace bool var reuseport bool flag.IntVar(&port, "port", 5000, "server port") flag.BoolVar(&udp, "udp", false, "listen on udp") flag.BoolVar(&reuseport, "reuseport", false, "reuseport (SO_REUSEPORT)") flag.BoolVar(&trace, "trace", false, "print packets to console") flag.IntVar(&loops, "loops", 0, "num loops") flag.Parse() var events gnet.Events events.NumLoops = loops events.OnInitComplete = func(srv gnet.Server) (action gnet.Action) { log.Printf("echo server started on port %d (loops: %d)", port, srv.NumLoops) if reuseport { log.Printf("reuseport") } return } events.React = func(c gnet.Conn, inBuf *ringbuffer.RingBuffer) (out []byte, action gnet.Action) { top, tail := inBuf.PreReadAll() out = append(top, tail...) inBuf.Reset() if trace { log.Printf("%s", strings.TrimSpace(string(top)+string(tail))) } return } scheme := "tcp" if udp { scheme = "udp" } log.Fatal(gnet.Serve(events, fmt.Sprintf("%s://:%d", scheme, port))) }
gnet
目前支持的 I/O 事件以下:
OnInitComplete
當 server 初始化完成以後調用。OnOpened
當鏈接被打開的時候調用。OnClosed
當鏈接被關閉的時候調用。OnDetached
當主動摘除鏈接的時候的調用。React
當 server 端接收到從 client 端發送來的數據的時候調用。(你的核心業務代碼通常是寫在這個方法裏)Tick
服務器啓動的時候會調用一次,以後就以給定的時間間隔定時調用一次,是一個定時器方法。PreWrite
預先寫數據方法,在 server 端寫數據回 client 端以前調用。Go Version: go1.12.9 linux/amd64 OS: Ubuntu 18.04 CPU: 8 Virtual CPUs Memory: 16.0 GiB
Go Version: go version go1.12.9 darwin/amd64 OS: macOS Mojave 10.14.6 CPU: 4 CPUs Memory: 8.0 GiB
gnet
的源碼容許用戶在遵循 MIT 開源證書 規則的前提下使用。
gnet 還在持續開發的過程當中,因此這個倉庫的代碼和文檔會一直持續更新,若是你對 gnet 感興趣的話,歡迎給這個開源庫貢獻你的代碼~~