gnet
gnet copied to clipboard
lockFreeQueue的gc问题
lock_free_queue.go的Enqueue()函数内的n := &node{value: task}
会调用到runtime.newobject和runtime.mallocgc,
Enqueue()频繁调用时,是否会有gc问题,是否考虑用类似sync.Pool的形式来管理node
你可以测一下,然后把数据贴出来看看,看看是不是的确会有很大影响。
1.新增的测试代码/cmd/main.go
type testCodec struct {
}
func (cc *testCodec) Encode(c gnet.Conn, buf []byte) (out []byte, err error) {
return buf, nil
}
func (cc *testCodec) Decode(c gnet.Conn) ([]byte, error) {
var buf innerBuffer
buf = c.Read()
msg, _ := buf.readN(4)
if msg == nil {
return nil, nil
}
c.ShiftN(4)
return msg, nil
}
type testServer struct {
*gnet.EventServer
svr gnet.Server
protoAddr string
workerPool *goroutine.Pool
}
func (s *testServer) React(packet []byte, c gnet.Conn) (out []byte, action gnet.Action) {
data := append([]byte{}, packet...)
_ = s.workerPool.Submit(func() {
_ = c.AsyncWrite(data)
})
return nil, gnet.None
}
func main() {
f, _ := os.OpenFile("gate-cpu.pprof", os.O_CREATE|os.O_RDWR, 0644)
_ = pprof.StartCPUProfile(f)
defer func() {
pprof.StopCPUProfile()
f.Close()
}()
ts := &testServer{
protoAddr: "tcp4://0.0.0.0:9999",
workerPool: goroutine.Default(),
}
go func() {
time.Sleep(70 * time.Second)
_ = gnet.Stop(context.TODO(), ts.protoAddr)
}()
err := gnet.Serve(ts,
ts.protoAddr,
gnet.WithLockOSThread(true),
gnet.WithNumEventLoop(3),
gnet.WithReuseAddr(true),
gnet.WithTCPNoDelay(gnet.TCPNoDelay),
gnet.WithCodec(&testCodec{}),
gnet.WithLoadBalancing(gnet.LeastConnections))
fmt.Println("serve", err)
}
2.go tool pprof数据: Showing nodes accounting for 137.59s, 86.26% of 159.51s total Dropped 228 nodes (cum <= 0.80s) Showing top 10 nodes out of 65 flat flat% sum% cum cum% 83.39s 52.28% 52.28% 83.39s 52.28% runtime.futex 35.05s 21.97% 74.25% 36.85s 23.10% syscall.Syscall 13.13s 8.23% 82.48% 13.58s 8.51% syscall.Syscall6 1.17s 0.73% 83.22% 65.22s 40.89% github.com/panjf2000/gnet/internal/netpoll.(*Poller).Polling 0.92s 0.58% 83.79% 3.53s 2.21% runtime.mallocgc
3.runtime.mallocgc相关的调用 gnet(*Conn).AsyncWrite -> runtime.mallocgc gnet(*Conn).AsyncWrite -> runtime.newobject -> runtime.mallocgc gnet(*Conn).AsyncWrite -> netpoll(*Poller).Tigger -> runtime.newobject -> runtime.mallocgc main(*testServer).React -> runtime.growslice -> runtime.mallocgc