经过半年的改进,目前关闭 handleLoop 的改进已经接近尾声,目前针对一个网络连接已经能够做到:
1 只有一个 read goroutine 专门处理读请求;
2 在业务处理逻辑的 goroutine 中同步处理写请求。
这个处理方法能否大幅度减少网络连接相关的 goroutine 的数量,在处理小包[<100k] 的情况下,基本上每次写请求发送都能成功,但是在处理网络打包[>= 8MiB] 的情况下,还是有很大概率会失败,其本质是 tcp/udp 的发送缓冲区有限,对待大包需要循环多次尝试发送。所以下一步的工作,个人觉得是不是可以专门启动一个处理写请求的 goroutine pool,其大小有限如 16,每个 goroutine 有一个请求队列【每个队列称为 wQ,16 个 wQ 就是一个 wQArray】,则写请求处理步骤就变成了:
1 业务方调用 session.WritePkg(pkg, timeout) 发送;
2 session.WritePkg(pkg, timeout) 先调用 pkg.Write() 接口把 pkg 序列化成字节流后,把 session.fd 和 字节流包装成一个 struct【暂称为 type sessionPkg struct { s []byte, fd int, timeout time.Duration, ackQ struct{} }】,然后放入一个 wQ【wQ = wQArray[session.fd % 16],取模运算可以保证每个 fd 网络请求都交给同一个 goroutine,保证发送顺序性】,然后以 select{ case <- time.After(@timeout); case a := <- sessionPkg.ackQ} 方式同步等待;
3 每个发送 goroutine 不断从 wQ 内取出 sessionPkg,然后循环发送;
发送方式可能为最多发送 10 次,每次时间间隔是 sessionPkg.timeout / 10。中间任何一次发送成功就返回,10 次发送失败就返回发送失败,不要影响 wQ 中后续 sessionPkg 的处理。
经过半年的改进,目前关闭 handleLoop 的改进已经接近尾声,目前针对一个网络连接已经能够做到:
1 只有一个 read goroutine 专门处理读请求;
2 在业务处理逻辑的 goroutine 中同步处理写请求。
这个处理方法能否大幅度减少网络连接相关的 goroutine 的数量,在处理小包[<100k] 的情况下,基本上每次写请求发送都能成功,但是在处理网络打包[>= 8MiB] 的情况下,还是有很大概率会失败,其本质是 tcp/udp 的发送缓冲区有限,对待大包需要循环多次尝试发送。所以下一步的工作,个人觉得是不是可以专门启动一个处理写请求的 goroutine pool,其大小有限如 16,每个 goroutine 有一个请求队列【每个队列称为 wQ,16 个 wQ 就是一个 wQArray】,则写请求处理步骤就变成了:
1 业务方调用 session.WritePkg(pkg, timeout) 发送;
2 session.WritePkg(pkg, timeout) 先调用 pkg.Write() 接口把 pkg 序列化成字节流后,把 session.fd 和 字节流包装成一个 struct【暂称为 type sessionPkg struct { s []byte, fd int, timeout time.Duration, ackQ struct{} }】,然后放入一个 wQ【wQ = wQArray[session.fd % 16],取模运算可以保证每个 fd 网络请求都交给同一个 goroutine,保证发送顺序性】,然后以 select{ case <- time.After(@timeout); case a := <- sessionPkg.ackQ} 方式同步等待;
3 每个发送 goroutine 不断从 wQ 内取出 sessionPkg,然后循环发送;
发送方式可能为最多发送 10 次,每次时间间隔是 sessionPkg.timeout / 10。中间任何一次发送成功就返回,10 次发送失败就返回发送失败,不要影响 wQ 中后续 sessionPkg 的处理。