不懂就问, Golang 带阻塞的高性能队列最佳实践是啥? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
lithbitren
V2EX    Go 编程语言

不懂就问, Golang 带阻塞的高性能队列最佳实践是啥?

  •  
  •   lithbitren 2020-04-11 11:38:47 +08:00 5500 次点击
    这是一个创建于 2013 天前的主题,其中的信息可能已经有所发展或是发生改变。
    像 Map 类型,可以无脑加锁实现共享数据,也可以直接用 sync.Map 来实现,前者在数据规模增大时性能会陡降,后者性能则平滑稳定,和一般语言一样,相同的需求,优先选择标准库里有的一般都是最佳的。

    可是对于队列来说,不管是 fifo 队列,还是栈和堆,在标准库里好像并没有并发的实现,无脑加锁倒是可以,参考 sync.Map 源码写一个理论上也不是不行,但有没有更优或更简洁的实现方法呢,最好是满足定容队列满了 put 方法和队列为空时 get 方法都自带阻塞的。
    21 条回复    2020-04-12 12:41:46 +08:00
    unixeno
        1
    unixeno  
       2020-04-11 11:43:42 +08:00 via Android
    chan
    useben
        2
    useben  
       2020-04-11 11:47:59 +08:00
    chan 就是你说的特性...
    lithbitren
        3
    lithbitren  
    OP
       2020-04-11 12:01:56 +08:00
    @useben
    @unixeno
    chan 可实现不定容的读写阻塞,但咋实现定容的写入阻塞啊?
    DCCooper
        4
    DCCooper  
       2020-04-11 12:03:12 +08:00 via iPhone
    @lithbitren #3 buffer ?
    felix021
        5
    felix021  
       2020-04-11 12:05:42 +08:00
    go 的 channel 貌似底层实现用的还是锁,github 上有第三方的 lockfree ring buffer,具体叫啥忘了,可以搜一下。
    lithbitren
        6
    lithbitren  
    OP
       2020-04-11 12:06:11 +08:00
    @DCCooper 是说类似于 make(chan int 10)这种写法吗?
    susecjh data-uid=
        7
    susecjh  
       2020-04-11 12:08:29 +08:00
    @lithbitren make(chan int, 10)这样不就是定容吗
    feelinglucky
        8
    feelinglucky  
       2020-04-11 12:08:30 +08:00
    @lithbitren 定容的意思是固定容量吗?或者并发数?那直接设个长度不就好了吗…
    lithbitren
        9
    lithbitren  
    OP
       2020-04-11 12:10:04 +08:00
    chan 还有问题,不知道无法监控容量情况,而且也只是实现了 fifo,实现 filo 和优先队列似乎也挺麻烦。
    reus
        10
    reus  
       2020-04-11 12:10:08 +08:00
    思而不学
    zhs227
        11
    zhs227  
       2020-04-11 12:27:36 +08:00
    你说的这个可以参考一下 buffered chan 。申请 chan 的时候指定长度即可。
    ch := make(chan []struct{}, 1000)
    监控容量情况更是简单,len(ch)就是当前队列中未处理容量。
    lithbitren
        12
    lithbitren  
    OP
       2020-04-11 12:38:59 +08:00
    @susecjh
    @zhs227
    谢谢,懂了,还有个小问题,就是把 chan 的传递都放在 go 里面,不管是否阻塞,程序都会直接结束吗?我之前因为这个以未 chan 加上 buffer 也不是阻塞的。
    lithbitren
        13
    lithbitren  
    OP
       2020-04-11 12:42:22 +08:00
    用了 sync.WaitGroup 才能让程序停下来,等待死锁报错的出现。
    lithbitren
        14
    lithbitren  
    OP
       2020-04-11 12:51:52 +08:00
    @reus 大佬教训的是。
    lithbitren
        15
    lithbitren  
    OP
       2020-04-11 13:03:22 +08:00
    因为之前用 python 比较多,队列、栈、堆在标准库都是有实现的,全部仍在子线程里也会因为定容死锁会导致程序无法关闭,被 go 的一些特性迷惑了,还需要进一步理解 go 。

    队列的问题姑且算是解决了,栈和堆的同步实现似乎也找不到啥资料。
    yuikns
        16
    yuikns  
       2020-04-11 13:18:54 +08:00   1
    队列的话我自己 wrap 了一个。
    https://github.com/argcv/stork/blob/master/schd/task_queue.go
    如果需要监控 capacity 我可能进一步再在这个 struct 中加
    yuikns
        17
    yuikns  
       2020-04-11 13:23:26 +08:00
    栈和堆其实可以也可以用一个 buffer 实现。不过没有 template 构建一个 general 的东西比较麻烦,go 自己的 pool 居然还是 interface,出入都加个类型切换,感觉有点粗糙。
    shujun
        18
    shujun  
       2020-04-11 13:50:19 +08:00 via iPhone
    自其实这种 自己封装一个很简单的。


    ringbuffer +chan, 比自己加锁效率高
    lithbitren
        19
    lithbitren  
    OP
       2020-04-12 08:53:46 +08:00
    @shujun 谢谢大佬提示,ringbuffer 原理倒是没啥问题,在 golang 的具体实现中是把 chan 装进 container 的 ring 里面(还是说直接用数组就行),然后进行转圈原子操作吗?还有 buffer 大小一般怎么设定啊,其他一般语言都是号称无锁实现的,而且就算有管道机制也和 golang 的 chan 不尽相同,golang 实现还有点懵懂。
    lithbitren
        20
    lithbitren  
    OP
       2020-04-12 09:31:43 +08:00
    读了下 ring 的源码,除 interface 好像没啥了,其他环形实现似乎上也没啥区别的样子
    fumeboy
        21
    fumeboy  
       2020-04-12 12:41:46 +08:00 via iPhone
    刚好在看 ringbuffer,还在苦恼看不懂它的作用……
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5602 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 03:08 PVG 11:08 LAX 20:08 JFK 23:08
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86