Commit 12ad9b43 authored by Rob Pike's avatar Rob Pike

fmt: replace channel cache with slice.

Simpler concept, and it turns a queue into a stack.
Speeds up benchmarks noticeably.

Before:
fmt_test.BenchmarkSprintfEmpty	10000000	       282 ns/op
fmt_test.BenchmarkSprintfString	 2000000	       910 ns/op
fmt_test.BenchmarkSprintfInt	 5000000	       723 ns/op
fmt_test.BenchmarkSprintfIntInt	 1000000	      1071 ns/op
fmt_test.BenchmarkSprintfPrefixedInt	 1000000	      1108 ns/op
fmt_test.BenchmarkScanInts	    1000	   2239510 ns/op
fmt_test.BenchmarkScanRecursiveInt	    1000	   2365432 ns/op

After:
fmt_test.BenchmarkSprintfEmpty	10000000	       232 ns/op
fmt_test.BenchmarkSprintfString	 2000000	       837 ns/op
fmt_test.BenchmarkSprintfInt	 5000000	       590 ns/op
fmt_test.BenchmarkSprintfIntInt	 2000000	       910 ns/op
fmt_test.BenchmarkSprintfPrefixedInt	 2000000	       996 ns/op
fmt_test.BenchmarkScanInts	    1000	   2210715 ns/op
fmt_test.BenchmarkScanRecursiveInt	    1000	   2367800 ns/op

R=rsc, r
CC=golang-dev
https://golang.org/cl/5151044
parent 1a13f9b8
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"io" "io"
"os" "os"
"reflect" "reflect"
"sync"
"unicode" "unicode"
"utf8" "utf8"
) )
...@@ -78,34 +79,37 @@ type pp struct { ...@@ -78,34 +79,37 @@ type pp struct {
} }
// A cache holds a set of reusable objects. // A cache holds a set of reusable objects.
// The buffered channel holds the currently available objects. // The slice is a stack (LIFO).
// If more are needed, the cache creates them by calling new. // If more are needed, the cache creates them by calling new.
type cache struct { type cache struct {
saved chan interface{} mu sync.Mutex
saved []interface{}
new func() interface{} new func() interface{}
} }
func (c *cache) put(x interface{}) { func (c *cache) put(x interface{}) {
select { c.mu.Lock()
case c.saved <- x: if len(c.saved) < cap(c.saved) {
// saved in cache c.saved = append(c.saved, x)
default:
// discard
} }
c.mu.Unlock()
} }
func (c *cache) get() interface{} { func (c *cache) get() interface{} {
select { c.mu.Lock()
case x := <-c.saved: n := len(c.saved)
return x // reused from cache if n == 0 {
default: c.mu.Unlock()
return c.new() return c.new()
} }
panic("not reached") x := c.saved[n-1]
c.saved = c.saved[0 : n-1]
c.mu.Unlock()
return x
} }
func newCache(f func() interface{}) *cache { func newCache(f func() interface{}) *cache {
return &cache{make(chan interface{}, 100), f} return &cache{saved: make([]interface{}, 0, 100), new: f}
} }
var ppFree = newCache(func() interface{} { return new(pp) }) var ppFree = newCache(func() interface{} { return new(pp) })
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment