V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
assiadamo
V2EX  ›  Go 编程语言

在 go net 库实现了 I/O 多路复用的情况下,还需要自己实现一套吗?

  •  
  •   assiadamo · 2023-09-11 18:27:44 +08:00 · 2026 次点击
    这是一个创建于 438 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 多路复用的机制吗?

    15 条回复    2023-09-13 15:57:17 +08:00
    coderxy
        1
    coderxy  
       2023-09-11 19:01:29 +08:00   ❤️ 1
    一般是一个连接给一个协程去处理。 问题嘛,就是严格说起来协程起多了也不够极致高性能(极致的高性能应该是有请求才需要协程去处理)。 但是实际上直接用默认的就够了。
    assiadamo
        2
    assiadamo  
    OP
       2023-09-11 19:16:11 +08:00 via Android
    @coderxy 按我老 javaer 的做法,会是创建几个 channel ,读 conn 的 goroutine 只会产出协议对象,根据业务或其他 hash 到不同的 channel 中,固定的几个 goroutine 读取协议对象进行业务处理,这里把 goroutine 当线程用了
    coderxy
        3
    coderxy  
       2023-09-11 19:23:40 +08:00   ❤️ 1
    @assiadamo 没必要,因为 goroutine 很轻量级,没必要再折腾一圈
    securityCoding
        4
    securityCoding  
       2023-09-11 19:33:47 +08:00   ❤️ 1
    不是高并发的情况使用 go net 原生 api 就好了保持简单,如果是 rpc 或者高并发场景可以看下 gnet
    1423
        5
    1423  
       2023-09-11 19:37:31 +08:00
    就应该这么用
    cosiner
        6
    cosiner  
       2023-09-11 19:46:10 +08:00
    可以这样理解, go runtime 是一个 epoll 框架, goroutine 是 callback, 所以业务层没必要再去做异步了, 真到了 goroutine 太多调度影响性能, 那时候才需要做选择, 修改架构
    voidmnwzp
        7
    voidmnwzp  
       2023-09-11 20:25:42 +08:00 via iPhone
    goroutine 也会占内存,但开销跟线程比不值一提,有些人会为了机制的内存性能重新在 goroutine 层面封装了 epoll ,我感觉没啥必要
    BBCCBB
        8
    BBCCBB  
       2023-09-11 20:30:20 +08:00
    性能要求高的网络框架一般都会搞个 netty 那种模型. stackless 协程应该是可以不搞 netty 网络模型. 但 go 是 stackful.

    一个连接两个 goroutine 不适用于超级多的网络连接.
    lesismal
        9
    lesismal  
       2023-09-11 20:51:06 +08:00
    绝大多数人处理的连接数都不算大、用标准库足够了。

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

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

    @securityCoding #4 gnet 自己支持的东西太少了,扩展起来也比较难,欢迎 pk (性能、功能、易用性都可以 pk )
    happy32199
        10
    happy32199  
       2023-09-11 22:47:32 +08:00 via iPhone
    fasthttp ? 性能提高很多,但是不稳定
    Nazz
        11
    Nazz  
       2023-09-11 22:48:35 +08:00 via Android
    需要控制最大并发,用 chan 简单封装下
    assiadamo
        12
    assiadamo  
    OP
       2023-09-11 23:29:09 +08:00 via Android
    我是想用来写游戏服务器的,有状态长连接
    lesismal
        13
    lesismal  
       2023-09-12 01:03:10 +08:00   ❤️ 1
    @assiadamo #12

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


    所以除非是做上面的 3 中这一类,否则单个游服没多大在线量。普通在线量的场景,自己搞 epoll 这些框架的响应性能并不如标准库方案,因为通常需要 IO 与逻辑协程分离,跨协程的变量逃逸、变量生命周期不容易 pool 复用优化,还有其他一些细节,各种因素加起来,响应性能不如标准库方案。
    所以如果只是为了游戏服务性能、并且不是上面的 3 ,建议 OP 不用研究这个问题了,自己感兴趣倒是可以继续深入
    mengdodo
        14
    mengdodo  
       2023-09-12 14:18:15 +08:00
    @lesismal 一篇文章我看到了 5 个所以,哈哈
    lesismal
        15
    lesismal  
       2023-09-13 15:57:17 +08:00
    @mengdodo #14 网页回复随便打打字,见笑了,我下次注意!😋😋
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2803 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 09:32 · PVG 17:32 · LAX 01:32 · JFK 04:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.