【发布时间】:2017-12-15 03:35:18
【问题描述】:
我尝试实现一个golang tcp服务器,发现并发对我来说是满意的,但是CPU使用率太高(并发15W+/s,但是在24核的linux机器中CPU使用率在800%左右)。同时,一个 C++ tcp 服务器的使用率只有 200% 左右,具有相似的并发性(使用 libevent)。
以下代码是golang的demo:
func main() {
listen, err := net.Listen("tcp", "0.0.0.0:17379")
if err != nil {
fmt.Errorf(err.Error())
}
go acceptClient(listen)
var channel2 = make(chan bool)
<-channel2
}
func acceptClient(listen net.Listener) {
for {
sock, err := listen.Accept()
if err != nil {
fmt.Errorf(err.Error())
}
tcp := sock.(*net.TCPConn)
tcp.SetNoDelay(true)
var channel = make(chan bool, 10)
go read(channel, sock.(*net.TCPConn))
go write(channel, sock.(*net.TCPConn))
}
}
func read(channel chan bool, sock *net.TCPConn) {
count := 0
for {
var buf = make([]byte, 1024)
n, err := sock.Read(buf)
if err != nil {
close(channel)
sock.CloseRead()
return
}
count += n
x := count / 58
count = count % 58
for i := 0; i < x; i++ {
channel <- true
}
}
}
func write(channel chan bool, sock *net.TCPConn) {
buf := []byte("+OK\r\n")
defer func() {
sock.CloseWrite()
recover()
}()
for {
_, ok := <-channel
if !ok {
return
}
_, writeError := sock.Write(buf)
if writeError != nil {
return
}
}
}
我通过 redis-benchmark 使用多客户端测试了这个 tcp 服务器:
redis-benchmark -h 10.100.45.2 -p 17379 -n 1000 -q script load "redis.call('set','aaa','aaa')"
我还通过 pprof 分析了我的 golang 代码,据说 CPU 在系统调用上花费了很多时间: enter image description here
【问题讨论】:
-
这可能更适合代码审查。一些想法:您使用的通道比需要的多,并且您错过了对套接字类型断言的检查
-
我对此毫无用处(我只能建议添加睡眠....),但很感兴趣。你介意在 ml 上发帖吗groups.google.com/forum/#!forum/golang-nuts
-
大部分时间花在 syscall for io 上是你所期望的。你制造了很多垃圾,也许 GC 占用了额外的时间。请注意,Go 程序中的总 CPU 使用率预计会更高,因为 Go 程序可能只是做得更多,但您应该能够获得相当接近的吞吐量。
-
@PasserBy 是的,我为每个socket连接创建了一个通道,我这样做是为了提高socket连接的并发性,这个demo只是为了测试golang socket性能,这个例子我没有做套接字类型断言。您认为过多的频道会导致 CPU 使用率过高吗?
标签: c++ go tcp socket.io libevent