如何减少 golang tcp 服务器中的 cpu 使用率?

     2023-02-16     124

关键词:

【中文标题】如何减少 golang tcp 服务器中的 cpu 使用率?【英文标题】:how can I reduce cpu usage in a golang tcp server? 【发布时间】: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 程序可能只是做得更多,但您应该能够获得相当接近的吞吐量。 Go toolchain includes a strong profiler. @PasserBy 是的,我为每个socket连接创建了一个通道,我这样做是为了提高socket连接的并发性,这个demo只是为了测试golang socket性能,这个例子我没有做套接字类型断言。您认为过多的频道会导致 CPU 使用率过高吗? 【参考方案1】:

我认为在这种情况下,将读写与通道并行化不会为您提供更好的性能。你应该尽量减少内存分配和系统调用(写函数可能会做很多系统调用)

你可以试试这个版本吗?

package main

import (
    "bytes"
    "fmt"
    "net"
)

func main() 
    listen, err := net.Listen("tcp", "0.0.0.0:17379")
    if err != nil 
        fmt.Errorf(err.Error())
    
    acceptClient(listen)


func acceptClient(listen net.Listener) 
    for 
        sock, err := listen.Accept()
        if err != nil 
            fmt.Errorf(err.Error())
        
        tcp := sock.(*net.TCPConn)
        tcp.SetNoDelay(true)
        go handleConn(tcp) // less go routine creation but no concurrent read/write on the same conn
    


var respPattern = []byte("+OK\r\n")

// just one goroutine per conn
func handleConn(sock *net.TCPConn) 
    count := 0
    buf := make([]byte, 4098) // Do not create a new buffer each time & increase the buff size
    defer sock.Close()

    for 
        n, err := sock.Read(buf)
        if err != nil 
            return
        
        count += n
        x := count / 58
        count = count % 58
        resp := bytes.Repeat(respPattern, x) // can be optimize
        _, writeError := sock.Write(resp) // do less syscall
        if writeError != nil 
            return
        
    

【讨论】:

golang中解决tcp传输中的粘包问题

...的小伙伴应该都知道粘包问题,举个例子:比如客户端在和服务器进行通信采用的是json格式的数据包。那么此时Client和Server的数据交互流程应该如下:ClientSendJs 查看详情

如何减少程序的CPU使用率?

】如何减少程序的CPU使用率?【英文标题】:HowtoreduceCPUusageofaprogram?【发布时间】:2009-03-0712:33:25【问题描述】:我编写了一个多线程程序,该程序使用大量浮点运算进行一些CPU繁重的计算。更具体地说,它是一个逐帧比较动画... 查看详情

如何不从 curl-multi 返回数据并减少 CPU 使用率?

...个请求返回都需要一些时间,所以我的脚本应该等到远程服务器上的处理完成。这50个请求中的每一个都返回大量我不需要的数据( 查看详情

如何减少 Tensorflow/Keras 使用的 CPU 数量?

】如何减少Tensorflow/Keras使用的CPU数量?【英文标题】:HowcanIreducethenumberofCPUsusedbyTensorlfow/Keras?【发布时间】:2020-01-1509:56:59【问题描述】:我使用的是Tensorflow2.0的Kerasapi。在我的Keras模型上调用fit时,它使用所有可用的CPU。我想... 查看详情

如何在golang中解析请求中的json? [关闭]

】如何在golang中解析请求中的json?[关闭]【英文标题】:howtoparsethejsonintherequestingolang?[closed]【发布时间】:2021-07-1108:47:48【问题描述】:数据:仅提取典型结构"logs":["points":[[30402984,1618566621000],[32146400,1618566636000]],"tags.metric":"name"... 查看详情

php与golang如何通信?

PHP与Golang如何通信?最近遇到的一个场景:php项目中需要使用一个第三方的功能(结巴分词),而github上面恰好有一个用Golang写好的类库。那么问题就来了,要如何实现不同语言之间的通信呢?常规的方案:用Golang写一个http/TCP... 查看详情

go中的udp服务器和客户端

...发送UDP消息时调用的Linux内核方法。虽然在Golang中看到TCP服务器的实现很普遍,但在UDP中看到相同的实现并不常见。除了UDP和TCP之间的许多差异之外,使用Go感觉它们非常相似,除了每个协议细节产生的小细节。如果您觉得一些Go... 查看详情

golang从入门到放弃

...ang搭建Windows开发环境。 tcp聊天软件开发:2、TCP监听服务器搭建。3、TCP服务器监听用户上线。4、TCP服务器群聊消息。5、TCP服务器用户修改名字、查询用户在线以及私聊功能6、TCP客户端命令行解析,根据参数连接服务器... 查看详情

golang中如何将一个进程绑定到一组cpu上?

】golang中如何将一个进程绑定到一组cpu上?【英文标题】:Howtobindaprocesstoasetofcpuingolang?【发布时间】:2021-09-2918:34:59【问题描述】:我使用os/execpkg来运行一个进程。我想检查它的cpu亲和力并修改它以将进程绑定到特定的cpu集。... 查看详情

如何减少 TCP connect() 系统调用超时?

】如何减少TCPconnect()系统调用超时?【英文标题】:HowtodecreaseTCPconnect()systemcalltimeout?【发布时间】:2014-08-1015:00:47【问题描述】:在下面的命令中,我启用文件/dev/tcp/10.10.10.1/80进行读写,并将其与文件描述符3相关联:$timeexec3&l... 查看详情

如何在 SORT 操作中减少 CPU

】如何在SORT操作中减少CPU【英文标题】:HowcanIreduceCPUinSORToperation【发布时间】:2018-07-2811:31:42【问题描述】:我正在使用DFSORT将磁带数据集复制到临时文件,并处理大约80000000条记录。复制数据集需要3个小时。有没有其他方法... 查看详情

我的多线程游戏一直处于 100% CPU。如何管理线程活动以减少 CPU 负载?

】我的多线程游戏一直处于100%CPU。如何管理线程活动以减少CPU负载?【英文标题】:Mymultithreadedgameisat100%CPUallthetime.HowcanImanagethreadactivitytoreducetheCPUload?【发布时间】:2014-01-3122:44:50【问题描述】:我有一个DirectX游戏,它在双核... 查看详情

如何减少我的应用程序的 CPU 消耗

】如何减少我的应用程序的CPU消耗【英文标题】:howtoreducethecpuconsumptionofmyapplication【发布时间】:2018-08-3011:55:39【问题描述】:一段时间以来,我的应用开始消耗大量CPU。一段时间以来,我的应用程序开始消耗大量CPU。我安装... 查看详情

如何减少控制器和业务层服务中的构造函数参数数量?

】如何减少控制器和业务层服务中的构造函数参数数量?【英文标题】:HowdoIreducethenumberofconstructorparametersincontrollersandbusinesslayerservices?【发布时间】:2017-03-1413:25:24【问题描述】:这是thisSOpost的改写。我发现使用中介模式可以... 查看详情

Golang 可见性或 CPU 线程缓存问题

...heissue【发布时间】:2019-05-2410:35:49【问题描述】:1)golang如何解决可见性问题?2)下面的代码有什么问题吗?packagemaintypeServicestructstopboolfunc(s*Service)Run()for!s.stop//Somelogicfunc(s*Service) 查看详情

服务器最大tcp连接数及调优汇总(代码片段)

启动线程数:启动线程数=【任务执行时间/(任务执行时间-IO等待时间)】*CPU内核数最佳启动线程数和CPU内核数量成正比,和IO阻塞时间成反比。如果任务都是CPU计算型任务,那么线程数最多不超过CPU内核数,因为启动再多线程... 查看详情

golang如何创建反向代理

...作反向代理。使用httputil创建反向代理。但是当我向代理服务器发出请求时,它会返回404错误。这是代理服务器代码packagemainimport("log""net/http""net/http/httputil"" 查看详情

golang创建一个简单的资源池,重用资源,减少gc负担

packagemain;import( "sync" "errors" "fmt")//代码参考《Go语言实战》中第7章并发模式Pool//如果哪个类型实现了Resource接口中的两个方法,我们就认为该类型是资源typeResourceinterface{ Close(); IsClosed()bool;}//工厂方法,用于创建新资源typeFactoryfunc... 查看详情