https://github.com/Allenxuxu/gev 是一个轻量, 快速的基于 Reactor 模式的非阻塞 TCP 网络库, 底层并不使用 golang.NET 库, 而是使用 epoll 和 kqueue, 因此它并不支持 Windows.
为什么有 gev
Golang 的 goroutine 虽然非常轻量, 但是每启动一个 goroutine 仍需要 4k 左右的内存. 读了鸟窝大佬的文章 [ 百万 Go TCP 连接的思考: epoll 方式减少资源占用 ] 后, 便去研究了了下 https://github.com/tidwall/evio .
evio 虽然非常快, 但是仍然存在一些问题, 便尝试去优化它, 于是有了 https://github.com/Allenxuxu/eviop 项目. 关于 evio 的问题可以看我的另一篇博文 [ Golang 网络库 evio 一些问题 / bug 和思考 https://hacpai.com/article/1565926947655 ] . 在优化 evio 完成 eviop 的过程中, 因为其网络模型的缘故, 愈加感觉修改它非常麻烦, 成本比重新搞一个还高.
最终决定自己重搞一个, 更加轻量, 不需要的全去掉. 加上大学时学习过 https://github.com/chenshuo/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 项目相同.
- .NET
- 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()
- }
来源: http://www.tuicool.com/articles/UvYRNvI