ZenQ

A thread-safe queue faster and more resource efficient than golang's native channels

MIT License

Stars
656
ZenQ - v2.8.4 Latest Release

Published by alphadose 8 months ago

Add compatibility with go 1.22 https://github.com/alphadose/ZenQ/pull/17 @Aoang

ZenQ - v2.8.3

Published by alphadose 9 months ago

Add Size() function which returns the number of items in the queue at any given time

ZenQ - v2.8.2

Published by alphadose almost 2 years ago

Add support for ppc64 and s390x CPU architectures

ZenQ - Fix assembly for 32 bit ARM devices

Published by alphadose about 2 years ago

Fix the assembly code in asm_arm.s and measure ZenQ's performance against channels for a low-end device (32 bit raspberry pi)

Device Info

  `.::///+:/-.        --///+//-:``    alphadose@neverwinter
 `+oooooooooooo:   `+oooooooooooo:    -------------------
  /oooo++//ooooo:  ooooo+//+ooooo.    OS: Raspbian GNU/Linux 11 (bullseye) armv7l
  `+ooooooo:-:oo-  +o+::/ooooooo:     Host: Raspberry Pi 4 Model B Rev 1.5
   `:oooooooo+``    `.oooooooo+-      Kernel: 5.15.32-v7l+
     `:++ooo/.        :+ooo+/.`       Uptime: 1 hour, 58 mins
        ...`  `.----.` ``..           Packages: 569 (dpkg)
     .::::-``:::::::::.`-:::-`        Shell: bash 5.1.4
    -:::-`   .:::::::-`  `-:::-       Terminal: /dev/pts/0
   `::.  `.--.`  `` `.---.``.::`      CPU: BCM2711 (4) @ 1.800GHz
       .::::::::`  -::::::::` `       Memory: 68MiB / 3838MiB
 .::` .:::::::::- `::::::::::``::.
-:::` ::::::::::.  ::::::::::.`:::-
::::  -::::::::.   `-::::::::  ::::
-::-   .-:::-.``....``.-::-.   -::-
 .. ``       .::::::::.     `..`..
   -:::-`   -::::::::::`  .:::::`
   :::::::` -::::::::::` :::::::.
   .:::::::  -::::::::. ::::::::
    `-:::::`   ..--.`   ::::::.
      `...`  `...--..`  `...`
            .::::::::::
             `.-::::-`

Benchstat of 20 runs

goos: linux
goarch: arm
name                                     time/op
_Chan_NumWriters1_InputSize600-4          230µs ± 4%
_ZenQ_NumWriters1_InputSize600-4          186µs ± 5%
_Chan_NumWriters3_InputSize60000-4       28.2ms ± 3%
_ZenQ_NumWriters3_InputSize60000-4       12.8ms ± 0%
_Chan_NumWriters8_InputSize6000000-4      4.14s ±10%
_ZenQ_NumWriters8_InputSize6000000-4      1.32s ± 1%
_Chan_NumWriters100_InputSize6000000-4    5.97s ± 5%
_ZenQ_NumWriters100_InputSize6000000-4    1.48s ± 5%
_Chan_NumWriters1000_InputSize7000000-4   7.23s ± 6%
_ZenQ_NumWriters1000_InputSize7000000-4   2.09s ± 4%
_Chan_Million_Blocking_Writers-4          20.3s ± 2%
_ZenQ_Million_Blocking_Writers-4          6.96s ± 4%

name                                     alloc/op
_Chan_NumWriters1_InputSize600-4          0.00B
_ZenQ_NumWriters1_InputSize600-4          0.00B
_Chan_NumWriters3_InputSize60000-4         227B ±27%
_ZenQ_NumWriters3_InputSize60000-4        77.9B ±91%
_Chan_NumWriters8_InputSize6000000-4      499B ±189%
_ZenQ_NumWriters8_InputSize6000000-4     1.49kB ± 4%
_Chan_NumWriters100_InputSize6000000-4   27.5kB ±19%
_ZenQ_NumWriters100_InputSize6000000-4   27.7kB ±42%
_Chan_NumWriters1000_InputSize7000000-4   290kB ± 5%
_ZenQ_NumWriters1000_InputSize7000000-4   135kB ± 8%
_Chan_Million_Blocking_Writers-4          325MB ± 0%
_ZenQ_Million_Blocking_Writers-4         76.2MB ± 3%

name                                     allocs/op
_Chan_NumWriters1_InputSize600-4           0.00
_ZenQ_NumWriters1_InputSize600-4           0.00
_Chan_NumWriters3_InputSize60000-4         1.00 ± 0%
_ZenQ_NumWriters3_InputSize60000-4         0.00
_Chan_NumWriters8_InputSize6000000-4      4.30 ±109%
_ZenQ_NumWriters8_InputSize6000000-4       19.2 ± 9%
_Chan_NumWriters100_InputSize6000000-4      171 ±13%
_ZenQ_NumWriters100_InputSize6000000-4      194 ±25%
_Chan_NumWriters1000_InputSize7000000-4   1.84k ± 3%
_ZenQ_NumWriters1000_InputSize7000000-4   1.09k ± 4%
_Chan_Million_Blocking_Writers-4          2.00M ± 0%
_ZenQ_Million_Blocking_Writers-4          1.00M ± 0%

Conclusion -> ZenQ scales better even in low-end devices

ZenQ - Improve selection performance

Published by alphadose about 2 years ago

  • Lowered the memory required by each selection object
  • Lowered the burden on selection reader goroutine leading to better latencies
ZenQ - Use golang 1.19 new native atomic types

Published by alphadose about 2 years ago

ZenQ - Performance Improvements

Published by alphadose over 2 years ago

ZenQ - List /v2 module to go-proxy

Published by alphadose over 2 years ago

ZenQ - Minor Optimization

Published by alphadose over 2 years ago

ZenQ - Improve slot determination performance

Published by alphadose over 2 years ago

ZenQ - Add support for specifying queue size

Published by alphadose over 2 years ago

ZenQ - Improve performance

Published by alphadose over 2 years ago

ZenQ - Improve performance and consistency

Published by alphadose over 2 years ago

ZenQ - Improve performance in the case ratio goroutines/cpu_cores is quite large

Published by alphadose over 2 years ago

ZenQ - Improve selection performance

Published by alphadose over 2 years ago

Improve the performance of select by adding direct_send and optimistic first pass read approach

ZenQ Select() is now comparable to channels although not as fast for large batch sizes

To improve ZenQ's selection performance even beyond this, the goroutine pointer itself has to be mutated for even faster data transfer during selections

With Input Batch Size: 60 and Num Concurrent Writers: 4

Chan Select Runner completed transfer in: 55.375µs
ZenQ Select Runner completed transfer in: 56.125µs
====================================================================

With Input Batch Size: 600 and Num Concurrent Writers: 4

Chan Select Runner completed transfer in: 181.334µs
ZenQ Select Runner completed transfer in: 432.75µs
====================================================================

With Input Batch Size: 6000 and Num Concurrent Writers: 4

Chan Select Runner completed transfer in: 936.042µs
ZenQ Select Runner completed transfer in: 4.410916ms
====================================================================

With Input Batch Size: 600000 and Num Concurrent Writers: 4

Chan Select Runner completed transfer in: 140.836375ms
ZenQ Select Runner completed transfer in: 380.546875ms
====================================================================
ZenQ - Select and Queue Closing Features added

Published by alphadose over 2 years ago

  • Selection added, no polling
  • Queue closing added, (now every call to Read() will also return whether the queue is currently exhausted or not)
  • Performance improved
ZenQ - More resource efficiency in cases of million goroutines

Published by alphadose over 2 years ago

ZenQ - New algorithm behaves more consistently

Published by alphadose over 2 years ago

name                                     old time/op    new time/op    delta
_ZenQ_NumWriters1_InputSize600-8           16.5µs ± 1%    17.9µs ± 1%   +8.65%  (p=0.000 n=28+29)
_ZenQ_NumWriters3_InputSize60000-8         2.85ms ± 0%    2.67ms ± 6%   -6.11%  (p=0.000 n=23+30)
_ZenQ_NumWriters8_InputSize6000000-8        417ms ± 0%     313ms ± 5%  -24.83%  (p=0.000 n=23+29)
_ZenQ_NumWriters100_InputSize6000000-8      741ms ± 3%     516ms ± 2%  -30.40%  (p=0.000 n=29+30)
_ZenQ_NumWriters1000_InputSize7000000-8     1.05s ± 1%     0.45s ± 9%  -57.58%  (p=0.000 n=28+30)
_ZenQ_Million_Blocking_Writers-8            7.01s ±44%    10.98s ± 4%  +56.54%  (p=0.000 n=30+28)

name                                     old alloc/op   new alloc/op   delta
_ZenQ_NumWriters1_InputSize600-8            0.00B          0.00B          ~     (all equal)
_ZenQ_NumWriters3_InputSize60000-8         28.9B ±111%    34.8B ±127%     ~     (p=0.268 n=30+29)
_ZenQ_NumWriters8_InputSize6000000-8        885B ±163%     671B ±222%     ~     (p=0.208 n=30+30)
_ZenQ_NumWriters100_InputSize6000000-8     16.2kB ±66%   13.3kB ±100%     ~     (p=0.072 n=30+30)
_ZenQ_NumWriters1000_InputSize7000000-8    62.4kB ±82%    2.4kB ±210%  -96.20%  (p=0.000 n=30+30)
_ZenQ_Million_Blocking_Writers-8           95.9MB ± 0%    95.5MB ± 0%   -0.41%  (p=0.000 n=28+30)

name                                     old allocs/op  new allocs/op  delta
_ZenQ_NumWriters1_InputSize600-8             0.00           0.00          ~     (all equal)
_ZenQ_NumWriters3_InputSize60000-8           0.00           0.00          ~     (all equal)
_ZenQ_NumWriters8_InputSize6000000-8        2.07 ±142%     1.40 ±186%     ~     (p=0.081 n=30+30)
_ZenQ_NumWriters100_InputSize6000000-8       53.5 ±50%     31.8 ±100%  -40.60%  (p=0.000 n=30+30)
_ZenQ_NumWriters1000_InputSize7000000-8       525 ±39%        6 ±227%  -98.95%  (p=0.000 n=30+30)
_ZenQ_Million_Blocking_Writers-8            1.00M ± 0%     0.99M ± 0%   -0.41%  (p=0.000 n=28+29)
ZenQ - Implement select{}

Published by alphadose over 2 years ago

  • Add select{} operation
  • Added benchmarks for select{} based transfer channels vs zenq
ZenQ - Save resources by parking extra goroutines

Published by alphadose over 2 years ago

In previous version of ZenQ, the tests timed out in cases of a million number of goroutines but this is handled in this version by parking extra goroutines

name                                     old time/op    new time/op    delta
_Chan_NumWriters1_InputSize600-8           23.2µs ± 0%    24.2µs ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters1_InputSize600-8           16.3µs ± 0%    16.7µs ± 0%   ~     (p=1.000 n=1+1)
_Chan_NumWriters3_InputSize60000-8         5.55ms ± 0%    6.19ms ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters3_InputSize60000-8         2.80ms ± 0%    2.85ms ± 0%   ~     (p=1.000 n=1+1)
_Chan_NumWriters8_InputSize6000000-8        694ms ± 0%     730ms ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters8_InputSize6000000-8        446ms ± 0%     421ms ± 0%   ~     (p=1.000 n=1+1)
_Chan_NumWriters100_InputSize6000000-8      1.59s ± 0%     1.60s ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters100_InputSize6000000-8      490ms ± 0%     736ms ± 0%   ~     (p=1.000 n=1+1)
_Chan_NumWriters1000_InputSize7000000-8     1.97s ± 0%     1.97s ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters1000_InputSize7000000-8     769ms ± 0%    1052ms ± 0%   ~     (p=1.000 n=1+1)


name                                     old alloc/op   new alloc/op   delta
_Chan_NumWriters1_InputSize600-8            0.00B          0.00B        ~     (all equal)
_ZenQ_NumWriters1_InputSize600-8            0.00B          0.00B        ~     (all equal)
_Chan_NumWriters3_InputSize60000-8          63.0B ± 0%     96.0B ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters3_InputSize60000-8          44.0B ± 0%      0.0B        ~     (p=1.000 n=1+1)
_Chan_NumWriters8_InputSize6000000-8       1.76kB ± 0%    0.24kB ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters8_InputSize6000000-8       1.52kB ± 0%    0.31kB ± 0%   ~     (p=1.000 n=1+1)
_Chan_NumWriters100_InputSize6000000-8     51.2kB ± 0%    35.9kB ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters100_InputSize6000000-8     5.27kB ± 0%   18.94kB ± 0%   ~     (p=1.000 n=1+1)
_Chan_NumWriters1000_InputSize7000000-8     492kB ± 0%     492kB ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters1000_InputSize7000000-8    16.6kB ± 0%    34.3kB ± 0%   ~     (p=1.000 n=1+1)

name                                     old allocs/op  new allocs/op  delta
_Chan_NumWriters1_InputSize600-8             0.00           0.00        ~     (all equal)
_ZenQ_NumWriters1_InputSize600-8             0.00           0.00        ~     (all equal)
_Chan_NumWriters3_InputSize60000-8           0.00           0.00        ~     (all equal)
_ZenQ_NumWriters3_InputSize60000-8           0.00           0.00        ~     (all equal)
_Chan_NumWriters8_InputSize6000000-8         5.00 ± 0%      2.00 ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters8_InputSize6000000-8         3.00 ± 0%      1.00 ± 0%   ~     (p=1.000 n=1+1)
_Chan_NumWriters100_InputSize6000000-8        163 ± 0%       147 ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters100_InputSize6000000-8       12.0 ± 0%      49.0 ± 0%   ~     (p=1.000 n=1+1)
_Chan_NumWriters1000_InputSize7000000-8     1.81k ± 0%     1.77k ± 0%   ~     (p=1.000 n=1+1)
_ZenQ_NumWriters1000_InputSize7000000-8      40.0 ± 0%     357.0 ± 0%   ~     (p=1.000 n=1+1)