Golang Go语言中 net 库实现了 I/O 多路复用,还需要自己实现一套吗?

发布于 1周前 作者 gougou168 来自 Go语言
ln, err := net.Listen("tcp", ":8080")
if err != nil {
	// handle error
}
for {
	conn, err := ln.Accept()
	if err != nil {
		// handle error
	}
	go handleConnection(conn)
}

这是 net package 中提供的例子 其中的 conn 虽然操作是“阻塞”式的,但底层的 fd 都是 non-blocking 的,由 go runtime 调用 epoll 等机制监听并唤醒 goroutine 进行操作,如果将不耗时的业务也放在该 goroutine 中,耗时的业务辅以其他的异步处理,这样做会有什么问题?在实际的工程中,会怎样操作?需要在业务层实现一套 I/O 多路复用的机制吗?


Golang Go语言中 net 库实现了 I/O 多路复用,还需要自己实现一套吗?

更多关于Golang Go语言中 net 库实现了 I/O 多路复用,还需要自己实现一套吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

16 回复

一般是一个连接给一个协程去处理。 问题嘛,就是严格说起来协程起多了也不够极致高性能(极致的高性能应该是有请求才需要协程去处理)。 但是实际上直接用默认的就够了。

更多关于Golang Go语言中 net 库实现了 I/O 多路复用,还需要自己实现一套吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


按我老 javaer 的做法,会是创建几个 channel ,读 conn 的 goroutine 只会产出协议对象,根据业务或其他 hash 到不同的 channel 中,固定的几个 goroutine 读取协议对象进行业务处理,这里把 goroutine 当线程用了

没必要,因为 goroutine 很轻量级,没必要再折腾一圈

不是高并发的情况使用 go net 原生 api 就好了保持简单,如果是 rpc 或者高并发场景可以看下 gnet

就应该这么用

可以这样理解, go runtime 是一个 epoll 框架, goroutine 是 callback, 所以业务层没必要再去做异步了, 真到了 goroutine 太多调度影响性能, 那时候才需要做选择, 修改架构

goroutine 也会占内存,但开销跟线程比不值一提,有些人会为了机制的内存性能重新在 goroutine 层面封装了 epoll ,我感觉没啥必要

性能要求高的网络框架一般都会搞个 netty 那种模型. stackless 协程应该是可以不搞 netty 网络模型. 但 go 是 stackful.

一个连接两个 goroutine 不适用于超级多的网络连接.

绝大多数人处理的连接数都不算大、用标准库足够了。

#3
#7
少量人需要处理海量连接、节约硬件、提高服务稳定性,nbio 简单压测 4c2g 跑 10w qps
https://www.v2ex.com/t/945827
标准库方案,差不多得 10g 左右内存了,cpu 核心数也得多些否则 gc 压力大、stw 不友好、稳定性低

另外 nbio 本身支持 http 、websocket 的连接采用标准库 Conn 、阻塞模式,只是用 nbio 的解析器,性能好、占用平衡

#4 gnet 自己支持的东西太少了,扩展起来也比较难,欢迎 pk (性能、功能、易用性都可以 pk )

fasthttp ? 性能提高很多,但是不稳定

需要控制最大并发,用 chan 简单封装下

我是想用来写游戏服务器的,有状态长连接

#12

游戏的单服务在线量不会太大,举几个例子:
1. MMORPG 同屏/同地图 CPU 计算量大、通常要分区限制单个区人数,所以单个游戏服在线也不会很大
2. MOBA/FPS 类也是 CPU 计算量大但没有大地图的广播消耗,单局游戏/单个房间也是玩家数量不大、最多也就 10 个、几十个,所以战斗服务器横向扩展堆机器就够用了
3. 反倒是那些轻量游戏,比如休闲类的、弱单机轻状态的游戏,玩家之间的互动性较少,也是可以横向扩容堆机器,但是这种对 CPU 消耗不高,所以如果用 Poller 来节省协程数量的话,单个服务能承载很多玩家在线、节省服务器软硬件资源


所以除非是做上面的 3 中这一类,否则单个游服没多大在线量。普通在线量的场景,自己搞 epoll 这些框架的响应性能并不如标准库方案,因为通常需要 IO 与逻辑协程分离,跨协程的变量逃逸、变量生命周期不容易 pool 复用优化,还有其他一些细节,各种因素加起来,响应性能不如标准库方案。
所以如果只是为了游戏服务性能、并且不是上面的 3 ,建议 OP 不用研究这个问题了,自己感兴趣倒是可以继续深入

一篇文章我看到了 5 个所以,哈哈

#14 网页回复随便打打字,见笑了,我下次注意!😋😋

在Golang(Go语言)中,net库确实已经实现了I/O多路复用机制,这主要是通过net包下的poll子包和一些底层的系统调用(如epoll在Linux上,kqueue在BSD上)来完成的。对于大多数应用场景,特别是网络服务器和客户端开发,Go语言内置的I/O多路复用机制已经足够高效和强大,无需开发者自己额外实现一套。

Go语言的运行时和net库在设计时已经充分考虑了并发和高性能的需求,通过goroutine和channel等机制,能够很好地处理大量的并发连接。在这些基础上,net库提供的接口已经封装好了底层的I/O多路复用逻辑,让开发者可以更加专注于业务逻辑的实现。

此外,Go语言还提供了net/http等高级库,这些库进一步简化了网络编程的复杂性,使得开发者可以更加轻松地构建出高性能的网络应用。

因此,除非你有非常特殊的需求(比如需要对I/O多路复用进行非常精细的控制,或者需要实现一些net库没有直接提供的特性),否则在Go语言中开发网络应用时,你完全可以直接使用net库和其他相关的高级库,而无需自己实现一套I/O多路复用机制。这样不仅可以提高开发效率,还可以确保你的应用更加稳定和可靠。

回到顶部