Skip to content

Instantly share code, notes, and snippets.

@rickb777
Created August 17, 2017 16:48
Show Gist options
  • Save rickb777/0a6009a92e4b60c0b36fdcdb599de664 to your computer and use it in GitHub Desktop.
Save rickb777/0a6009a92e4b60c0b36fdcdb599de664 to your computer and use it in GitHub Desktop.
Stabbycutyou/accumulator - revised to use templates for many types
// Package accumulator is a lightweight wrapper around an atomic.{{.UType}}, which
// allows you to easily increment a counter, and "flush" it to 0, returning the
// current value. A use case for this might be a timed reading in a stats system.
package accumulator
package accumulator
import (
"testing"
"time"
)
func Benchmark{{.UType}}Mutex(b *testing.B) {
c := New{{.UType}}()
for i := 0; i < b.N; i++ {
c.Incr()
}
}
func Test{{.UType}}Mutex(t *testing.T) {
c := New{{.UType}}()
for i := 0; i < 100; i++ {
c.Incr()
}
if c.Flush() != 100.0 {
t.Fail()
}
}
func Benchmark{{.UType}}MutexWithFlush(b *testing.B) {
c := New{{.UType}}()
for i := 0; i < b.N; i++ {
c.Incr()
if i%10000 == 0 {
c.Flush()
}
}
}
func Benchmark{{.UType}}MutexWithConcurrentFlush(b *testing.B) {
c := New{{.UType}}()
sleep, _ := time.ParseDuration("10ms")
go func() {
for {
time.Sleep(sleep)
c.Flush()
}
}()
for i := 0; i < b.N; i++ {
c.Incr()
if i%10000 == 0 {
c.Flush()
}
}
}
package accumulator
import (
"sync"
)
// {{.UType}} is a wrapper around a *{{.Type}}, interacted with via the atomic package
type {{.UType}} struct {
l sync.Mutex
n {{.Type}}
}
// New{{.UType}} returns a new pointer to an accumulator
func New{{.UType}}() *{{.UType}} {
return &{{.UType}}{n: 0}
}
// Incr incremenets the accumulator by 1
func (i *{{.UType}}) Incr() {
i.l.Lock()
i.n++
i.l.Unlock()
}
// IncrN incremenets the accumulator by 1
func (i *{{.UType}}) IncrN(n {{.Type}}) {
i.l.Lock()
i.n += n
i.l.Unlock()
}
// Flush resets the accumulator to 0, and returns the former value
func (i *{{.UType}}) Flush() {{.Type}} {
i.l.Lock()
n := i.n
i.n = 0
i.l.Unlock()
return n
}
package accumulator
import (
"testing"
"time"
)
func BenchmarkAtomic{{.UType}}(b *testing.B) {
c := New{{.UType}}()
for i := 0; i < b.N; i++ {
c.Incr()
}
}
func TestAtomic{{.UType}}(t *testing.T) {
c := New{{.UType}}()
for i := 0; i < 100; i++ {
c.Incr()
}
if c.Flush() != 100 {
t.Fail()
}
}
func BenchmarkAtomic{{.UType}}WithFlush(b *testing.B) {
c := New{{.UType}}()
for i := 0; i < b.N; i++ {
c.Incr()
if i%10000 == 0 {
c.Flush()
}
}
}
func BenchmarkAtomic{{.UType}}WithConcurrentFlush(b *testing.B) {
c := New{{.UType}}()
sleep, _ := time.ParseDuration("10ms")
go func() {
for {
time.Sleep(sleep)
c.Flush()
}
}()
for i := 0; i < b.N; i++ {
c.Incr()
}
}
package accumulator
import (
"sync/atomic"
)
// {{.UType}} is a wrapper around an *{{.Type}}, interacted with via the atomic package
type {{.UType}} struct {
n *{{.Type}}
}
// New{{.UType}} returns a new pointer to an accumulator
func New{{.UType}}() *{{.UType}} {
i := {{.Type}}(0)
return &{{.UType}}{n: &i}
}
// Incr incremenets the accumulator by 1
func (i *{{.UType}}) Incr() {
atomic.Add{{.UType}}(i.n, 1)
}
// IncrN incremenets the accumulator by the provided value n
func (i *{{.UType}}) IncrN(n {{.Type}}) {
atomic.Add{{.UType}}(i.n, n)
}
// Flush resets the accumulator to 0, and returns the former value
func (i *{{.UType}}) Flush() {{.Type}} {
return atomic.Swap{{.UType}}(i.n, 0)
}
# first, run
# go get github.com/rickb777/runtemplate
default:
runtemplate -tpl intAccumulator.tpl Type=int64
runtemplate -tpl intAccumulator.tpl Type=uint64
runtemplate -tpl intAccumulator.tpl Type=int32
runtemplate -tpl intAccumulator.tpl Type=uint32
runtemplate -tpl int_test.tpl Type=int32
runtemplate -tpl int_test.tpl Type=int64
runtemplate -tpl int_test.tpl Type=uint32
runtemplate -tpl int_test.tpl Type=uint64
runtemplate -tpl floatAccumulator.tpl Type=float32
runtemplate -tpl floatAccumulator.tpl Type=float64
runtemplate -tpl float_test.tpl Type=float32
runtemplate -tpl float_test.tpl Type=float64
clean:
rm -f *accumulator.go *_test.go
.PHONY: clean default
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment