V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
bushenx
V2EX  ›  问与答

Go 的并发模型的一些问题

  •  
  •   bushenx · 2021-02-12 21:58:57 +08:00 · 1925 次点击
    这是一个创建于 1410 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近在优化业务上的一块功能,现阶段这个功能会对用户的每个请求新建一个协程处理,但是个人感觉这样无节制的使用协程有些不妥。想在这上面优化一下,比如限制用户新建协程的数量。有这个想法但是具体实现应该如何做?有什么书籍或者文章介绍类似这样协程并发模型的,可以推荐学习一下吗?
    19 条回复    2021-02-19 14:05:40 +08:00
    pythonnoob
        1
    pythonnoob  
       2021-02-12 22:17:50 +08:00 via iPhone   ❤️ 1
    直接用消息队列削谷平峰,或者用令牌桶限制数量
    bushenx
        2
    bushenx  
    OP
       2021-02-12 22:23:35 +08:00 via Android
    @pythonnoob 令牌桶有使用,但是想在协程创建的地方也控制一下协程的并发数量,可以给支个招或者有什么别的渠道学习一下吗?
    matrix67
        3
    matrix67  
       2021-02-12 22:24:38 +08:00   ❤️ 1
    用户的每个请求当一个任务,丢到队列里面去,然后 go 开 worker 去解决任务。
    bushenx
        4
    bushenx  
    OP
       2021-02-12 22:26:29 +08:00 via Android
    @matrix67 当时是想到这个方法,但是如果用户接入量很多,队列是不是需要一个全局锁去保护,这样感觉有失性能。
    bushenx
        5
    bushenx  
    OP
       2021-02-12 22:28:19 +08:00 via Android
    我想能不能有什么并发模型能限制每个用户起协程的数量,但是又不会因为同步而损失太多性能。
    rrfeng
        6
    rrfeng  
       2021-02-13 00:01:54 +08:00 via Android
    千万级 goroutine 没什么问题。
    延时敏感的也不会用 go 吧。
    namaketa
        7
    namaketa  
       2021-02-13 00:55:23 +08:00 via Android
    一切性能问题都要问问自己为什么不能提配置 /加机器解决呢。
    协程调度开销已经很低了,特别对于重 io 任务。
    建议跑跑 benchmark 自己看调度耗时占比,再去判断要不要优化。
    golang 管道性能确实比较一般,可以多开几个管道。
    如果你真的有千万级别 /低时延 /重计算的任务,放过 go 吧。
    faker1
        8
    faker1  
       2021-02-13 01:56:59 +08:00   ❤️ 1
    1 楼的感觉可以, 实在想做感觉 可以参考 go 自己的任务调度, 锁的粒度放细, (全局,局部)类似分 group , 感觉这个是过度搞的,好像
    ginjedoad
        9
    ginjedoad  
       2021-02-13 08:15:41 +08:00
    使用协程池就好了。
    ginjedoad
        10
    ginjedoad  
       2021-02-13 08:19:27 +08:00   ❤️ 1
    比如这位同学写的稍微复杂了点。但是对于协程的限制数量级限制的同时,整体性能不升反降。https://github.com/panjf2000/ants

    “单机上百万上千万的同步批量任务处理现实意义不大,但是在异步批量任务处理方面有很大的应用价值,所以我个人觉得,Goroutine Pool 真正的价值还是在:

    限制并发的 goroutine 数量;
    复用 goroutine,减轻 runtime 调度压力,提升程序性能;
    规避过多的 goroutine 侵占系统资源( CPU&内存)。”
    sujin190
        11
    sujin190  
       2021-02-13 09:57:25 +08:00 via Android   ❤️ 1
    在线程外设计协程本来就是为了干这个的啊,每个请求一个协程,你们倒好,居然还怕协程创建太多,真是服了
    sujin190
        12
    sujin190  
       2021-02-13 10:04:02 +08:00 via Android
    之前做锁服务的时候测试过,每个请求一个协程,十万级 rps 并没有啥问题,想要更高确实需要协程复用,但这个过程必须是无锁的,无锁协程池并不是每个场景都能有的,web 这种真没啥必要
    bushenx
        13
    bushenx  
    OP
       2021-02-13 11:07:10 +08:00 via Android
    或许是我的表述不够明确,业务背景是服务会处理所有用户的请求,假设某个用户在某时间段请求数量剧增,这就导致会创建很多协程,而很多的协程会影响其他用户创建的协程。我是想减轻单个用户对所有用户的影响,所以限制协程数量。
    scnace
        14
    scnace  
       2021-02-14 20:54:20 +08:00 via Android
    你自己做个 benchmark 就知道了啊, 反正楼上的人说了你也不敢直接就这么干吧。。实在不行就上 goroutine pool 呗。。
    zxCoder
        15
    zxCoder  
       2021-02-15 00:48:12 +08:00
    歪个楼问一句,要看懂楼上大佬们所讨论的东西,大概要几年的工作 /golang 经验
    pythonnoob
        16
    pythonnoob  
       2021-02-19 11:39:27 +08:00 via iPhone
    @bushenx 加机器。除非到了加机器也解决不了的情况否则别做这种优化。
    pythonnoob
        17
    pythonnoob  
       2021-02-19 11:42:35 +08:00 via iPhone
    协程的调度器是无数大牛做出来的,一般人做所谓的优化很多时候会适得其反。请求激增的情况应该首先考虑加机器、前端或反代限流这些极其轻松的手段。
    pythonnoob
        18
    pythonnoob  
       2021-02-19 11:44:12 +08:00 via iPhone
    除非是 bat 、12306 这种体量,否则通过优化架构已经可以解决 99%的问题了
    bushenx
        19
    bushenx  
    OP
       2021-02-19 14:05:40 +08:00 via Android
    @pythonnoob 我的问题楼上的老哥已经给出答案了,就是实现一个协程池。因为我的逻辑是根据用户的请求创建协程,这很可能会导致协程被无休止创建。但是协程池就可以很好解决这个问题。在同步任务下协程池确实是没有必要的,go 运行时会有逻辑复用 g,但是这异步任务下协程池就可以很好的控制协程数量。我这个需求应该不算是性能优化,是极端情况下的一种保护措施。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3066 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 00:18 · PVG 08:18 · LAX 16:18 · JFK 19:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.