lfchan

package module
v0.0.0-...-e35a26a Latest Latest
Warning

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

Go to latest
Published: Mar 30, 2016 License: Apache-2.0 Imports: 3 Imported by: 0

README

lfchan GoDoc Build Status Go Report Card

--

A scalable lock-free channel.

  • Supports graceful closing.
  • Supports blocking and non-blocking operations.
  • Supports select.
  • Scales with the number of cores.

Install

go get github.com/OneOfOne/lfchan

Usage

import (
	"fmt"

	"github.com/OneOfOne/lfchan"
)

func main() {
	ch := lfchan.New() // or
	// ch := lfchan.NewSize(10) // buffered channel
	go ch.Send("hello", true)
	fmt.Printf("%s world", ch.Recv(true).(string))
}

Generate a typed channel

Generate the package:

go run "$GOPATH/src/github.com/OneOfOne/lfchan/gen.go" type [pkgName or . to embed the chan in the current package]

# primitve type
go run "$GOPATH/src/github.com/OneOfOne/lfchan/gen.go" string internal/stringChan

# or for using a non-native type
go run "$GOPATH/src/github.com/OneOfOne/lfchan/gen.go" github.com/OneOfOne/cmap.CMap internal/cmapChan

go run "$GOPATH/src/github.com/OneOfOne/lfchan/gen.go" github.com/OneOfOne/cmap.CMap

Use it in your code:

typed sub package
package main

// go run "$GOPATH/src/github.com/OneOfOne/lfchan/gen.go" string internal/stringChan

import (
	"fmt"

	"github.com/YOU/internal/stringChan"
)

func main() {
	ch := stringChan.New() // or
	// ch := stringChan.NewSize(10) // buffered channel
	go func() {
		go ch.Send("lfchan", true)
		ch.Send("hello", true)
	}()
	for s, ok := ch.Recv(true); ok; s, ok = ch.Recv(true) {
		fmt.Print(s, " ")
	}
	fmt.Println()
}

embed the type directly
package main

// go run "$GOPATH/src/github.com/OneOfOne/lfchan/gen.go" "[]*node" .

import (
	"fmt"
)

type node struct {
	v int
}

func main() {
	// notice how for embeded types the new func is called "new[Size]{TypeName}Chan()
	ch := newNodeChan() // or
	// ch := newSizeNodeChan(10) // buffered channel
	go func() {
		for i := 0; i < 10; i++ {
			ch.Send([]*Node{{i}, {i*i}}, true)
		}
	}()
	for ns, ok := ch.Recv(true); ok; ns, ok = ch.Recv(true) {
		for i, n := range ns {
			fmt.Println(i, n.v)
		}
	}
}

Known issues

  • Doesn't scale correctly on true SMP systems (issue #3).

  • Under high concurrency, ch.Len() can return -1 (issue #2) Fixed by commit bdddd90.

  • typed channels can't handle zero value primitve types correctly, for example it can't handle sending 0 on an int channel Fixed.

  • gen.go can't handle maps to non-native types.

Benchmark

# Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz
# Linux 4.4.5 x86_64

➜ go test -bench=. -benchmem -cpu 1,4,8 -benchtime 10s
BenchmarkLFChan         100000000              157 ns/op               8 B/op          1 allocs/op
BenchmarkLFChan-4       100000000              187 ns/op               8 B/op          1 allocs/op
BenchmarkLFChan-8       100000000              168 ns/op               8 B/op          1 allocs/op

BenchmarkChan           200000000             96.2 ns/op               8 B/op          1 allocs/op
BenchmarkChan-4         50000000               244 ns/op               8 B/op          1 allocs/op
BenchmarkChan-8         50000000               323 ns/op               8 B/op          1 allocs/op

PASS
ok      github.com/OneOfOne/lfchan      124.067s

check issue #3 for more benchmarks and updates.

FAQ

Why are you using runtime.Gosched?

  • Sadly, it is the only clean way to release the scheduler in a tight loop, Go doesn't provide any other way to yield, time.Sleep causes random allocations at times. sync/atomic.Value has access to internal funcs which can control the scheduler, however user code can't do that.

Isn't using a spinlock bad for the CPU?

  • Yes and no, using the spinlock and few sleeps in the code makes it very efficient even under idle conditions.

License

This project is released under the Apache v2. licence. See LICENCE for more details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SelectRecv

func SelectRecv(block bool, chans ...Receiver) (interface{}, bool)

SelectRecv returns the first available value from chans, if block is true, it blocks until a value is available. returns nil, false if all channels were empty and block is false.

func SelectSend

func SelectSend(block bool, v interface{}, chans ...Sender) bool

SelectSend sends v to the first available channel, if block is true, it blocks until a channel a accepts the value. returns false if all channels were full and block is false.

Types

type Chan

type Chan struct {
	// contains filtered or unexported fields
}

Chan is a lock free channel that supports concurrent channel operations.

func New

func New() Chan

New returns a new channel with the buffer set to 1

func NewSize

func NewSize(sz int) Chan

NewSize creates a buffered channel, with minimum length of 1, may adjust the size to fit better in the internal queue.

func (Chan) Cap

func (ch Chan) Cap() int

Cap returns the size of the internal queue

func (Chan) Close

func (ch Chan) Close()

Close marks the channel as closed

func (Chan) Closed

func (ch Chan) Closed() bool

Closed returns true if the channel have been closed

func (Chan) Len

func (ch Chan) Len() int

Len returns the number of elements queued

func (Chan) Recv

func (ch Chan) Recv(block bool) (interface{}, bool)

Recv blocks until a value is available and returns v, true, or if the channel is closed and the buffer is empty, it will return nil, false

func (Chan) RecvOnly

func (ch Chan) RecvOnly() RecvOnly

RecvOnly returns a receive-only channel.

func (Chan) Send

func (ch Chan) Send(v interface{}, block bool) bool

Send adds v to the buffer of the channel and returns true, if the channel is closed it returns false

func (Chan) SendOnly

func (ch Chan) SendOnly() SendOnly

SendOnly returns a send-only channel.

type Receiver

type Receiver interface {
	Recv(block bool) (interface{}, bool)
}

Receiver represents a Chan or RecvOnly.

type RecvOnly

type RecvOnly struct {
	// contains filtered or unexported fields
}

RecvOnly is a receive-only channel.

func (RecvOnly) Recv

func (ro RecvOnly) Recv(block bool) (interface{}, bool)

Recv is an alias for Chan.Recv.

type SendOnly

type SendOnly struct {
	// contains filtered or unexported fields
}

SendOnly is a send-only channel.

func (SendOnly) Send

func (so SendOnly) Send(v interface{}, block bool) bool

Send is an alias for Chan.Send.

type Sender

type Sender interface {
	Send(v interface{}, block bool) bool
}

Sender represents a Chan or SendOnly.

Directories

Path Synopsis
typed

Jump to

Keyboard shortcuts

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