https://github.com/negrel/ringo
:atom_symbol: A thread safe, lock free, efficient ring buffer library.
https://github.com/negrel/ringo
buffer circular circular-buffer go golang ring
Last synced: about 1 year ago
JSON representation
:atom_symbol: A thread safe, lock free, efficient ring buffer library.
- Host: GitHub
- URL: https://github.com/negrel/ringo
- Owner: negrel
- License: mit
- Created: 2020-03-19T21:54:49.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2024-06-04T07:15:55.000Z (almost 2 years ago)
- Last Synced: 2025-01-08T09:13:57.150Z (about 1 year ago)
- Topics: buffer, circular, circular-buffer, go, golang, ring
- Language: Go
- Homepage:
- Size: 26.4 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README

# :atom_symbol: Ringo - Fast, lock free ring buffers.
A thread safe, lock free, efficient ring buffer library.
Ringo is heavily inspired by [go-diodes](https://github.com/cloudfoundry/go-diodes/)
but aims to provide a more safe (no unsafe) alternative.
## Features
- :zap: [**Efficient**](https://github.com/negrel/ringo#zap-benchmarks)
- **Thread-safe** : manipulated via [atomics](https://pkg.go.dev/sync/atomic) operations.
- **Type-safe** : buffers are implemented using [Go 1.18 generics](https://go.dev/doc/tutorial/generics).
## Getting started
### Installation
Using **go get** :
```bash
go get github.com/negrel/ringo.git
```
Using **go modules** :
```go
package "your_package_name"
import (
"github.com/negrel/ringo"
)
func main() {
// Your code here
}
```
then
```bash
go mod tidy
```
### Example: Basic Use
```go
buffer := ringo.NewManyToOne[int](1024)
go func() {
for i := 0; i < math.MaxInt; i++ {
buffer.Push(i)
}
}()
ctx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(time.Minute)
cancel()
}()
poller := ringo.NewPoller(buffer, ringo.WithPollingContext[int](ctx))
for {
next, done, dropped := poller.Next()
// Writer is faster than reader, some data was overwritten.
if dropped > 0 {
log.Printf("lost %v int", dropped)
}
// Context canceled.
if done {
break
}
log.Print(next)
}
```
## Storage Layer
### OneToOne
OneToOne ring buffer isn't implemented as my private implementation didn't
provide any performance gain. Use ManyToOne.
### ManyToOne
The ManyToOne ring buffer is optimized for many producing (invoking Push())
go-routines and a single consuming (invoking TryNext()) go-routine. It is not
thread safe for multiple readers.
## Access Layer
### Poller
The Poller uses polling via time.Sleep(...) when Next() is invoked. While
polling might seem sub-optimal, it allows the producer to be completely
decoupled from the consumer. If you require very minimal push back on the
producer, then the Poller is a better choice. However, if you require several
ring buffers (e.g. one per connected client), then having several go-routines polling
(sleeping) may be hard on the scheduler.
### Waiter
The Waiter uses a conditional mutex to manage when the reader is alerted of new
data. While this method is great for the scheduler, it does have extra overhead
for the producer. Therefore, it is better suited for situations where you have
several ring buffers and can afford slightly slower producers.
## :zap: Benchmarks
```
goos: linux
goarch: amd64
pkg: github.com/negrel/ringo
cpu: AMD Ryzen 7 7840U w/ Radeon 780M Graphics
BenchmarkRing
BenchmarkRing-16 206156005 6.042 ns/op 16 B/op 0 allocs/op
BenchmarkManyToOne
BenchmarkManyToOne-16 40134350 30.07 ns/op 16 B/op 1 allocs/op
BenchmarkManyToOneWaiter
BenchmarkManyToOneWaiter-16 33045910 33.27 ns/op 16 B/op 1 allocs/op
BenchmarkManyToOnePoller
BenchmarkManyToOnePoller-16 34575518 34.47 ns/op 16 B/op 1 allocs/op
PASS
ok github.com/negrel/ringo 7.718s
```
## Known issues
If a ring buffer was to be written to 18446744073709551615+1 times it would overflow
a uint64. This will cause problems if the size of the ring buffer is not a power of
two (2^x). If you write into a ring buffer at the rate of one message every
nanosecond, without restarting your process, it would take you 584.54 years to
encounter this issue.
## :stars: Show your support
Please give a :star: if this project helped you!
## Acknowledgments
Atomic Icon by Vignesh Oviyan on Iconscout
## :scroll: License
MIT © Alexandre Negrel