OneOfOne / lfchan

A scalable lock-free channel.
Apache License 2.0
134 stars 5 forks source link

lfchan GoDoc Build Status Go Report Card

--

A scalable lock-free channel.

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

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?

Isn't using a spinlock bad for the CPU?

License

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