lfring

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 13, 2022 License: MIT Imports: 1 Imported by: 1

README

Lock free ring buffer

Go Report Card Go Reference GitHub license GitHub release

This repo is an implementation of lock-free ring buffer built on Golang.

You can find more information about this implementation at my blog post.

API

Below is the API and how to use it:

type RingBuffer interface {
    Offer(interface{}) (success bool)
    Poll() (value interface{}, success bool)
    SingleProducerOffer(valueSupplier func() (v interface{}, finish bool))
    SingleConsumerPoll(valueConsumer func(interface{}))
}

Generally, we can simply call Offer() and Poll() to use it like normal queue. Any types are acceptable, but for the memory efficiency concern, pointer is a better choice to handover by the ring buffer, no GC will happen during read/write.

We can create one as follows:

import (
    lfring "github.com/LENSHOOD/go-lock-free-ring-buffer"
)

buffer := lfring.New(lfring.Classical, 16)

The first argument of New() is the type of ring buffer, I currently provide two implementations, they both have same behavior, but benchmark test shows that the "NodeBased" one has better performance.

The second argument is capacity, which defines how big the ring buffer is (the calculation unit is the number of slots).

Method for special circumstance

There's two other methods you may notice at API:

  • SingleProducerOffer()
  • SingleConsumerPoll()

This two methods is to cover two special circumstances as: multi-producer single-consumer, and single-producer multi-consumer.

When the usage scenario is mpsc or spmc, use such method "may" improve the handover performance since in those scenarios we can safely discard some heavy operations.

However, the performance test(in my blog post) shows that SingleConsumerPoll() do improve the mpsc performance to about 1.4x, but SingleProducerOffer() become slower at spmc.

Performance

  1. Two type of lock-free ring buffer compare with go-channel at different capacities
  2. Two type of lock-free ring buffer compare with go-channel at different producers / consumers ratio
  3. Two type of lock-free ring buffer compare with go-channel at different threads

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BufferType

type BufferType int

BufferType contains different type names of ring buffer

const (
	// Classical ring buffer is a classical implementation of ring buffer
	Classical BufferType = iota

	// NodeBased is a type of ring buffer that implemented as node based,
	// see https://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
	NodeBased
)

type RingBuffer

type RingBuffer[T any] interface {
	Offer(T) (success bool)
	Poll() (value T, success bool)
	SingleProducerOffer(valueSupplier func() (v T, finish bool))
	SingleConsumerPoll(valueConsumer func(T))
	SingleConsumerPollVec(ret []T) (validCnt uint64)
}

RingBuffer defines the behavior of ring buffer

func New

func New[T any](t BufferType, capacity uint64) RingBuffer[T]

New build a RingBuffer with BufferType and capacity. Expand capacity as power-of-two, to make head/tail calculate faster and simpler

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL