1
0

Don't use defer for mutex unlocking (it currently adds ~200ns)

This commit is contained in:
Patrick Mylund Nielsen 2012-02-17 01:40:55 +01:00
parent 13b338b204
commit 91bd4334f1
2 changed files with 17 additions and 18 deletions

View File

@ -34,6 +34,8 @@ type Cache struct {
type cache struct {
DefaultExpiration time.Duration
Items map[string]*Item
// TODO: Calls to mu.Unlock are currently not deferred because defer
// adds ~200 ns (as of 792c7561af4b+ tip.)
mu sync.Mutex
janitor *janitor
}
@ -42,9 +44,8 @@ type cache struct {
// cache's default expiration time is used. If it is -1, the item never expires.
func (c *cache) Set(k string, x interface{}, d time.Duration) {
c.mu.Lock()
defer c.mu.Unlock()
c.set(k, x, d)
c.mu.Unlock()
}
func (c *cache) set(k string, x interface{}, d time.Duration) {
@ -66,13 +67,13 @@ func (c *cache) set(k string, x interface{}, d time.Duration) {
// or if the existing item has expired. Returns an error if not.
func (c *cache) Add(k string, x interface{}, d time.Duration) error {
c.mu.Lock()
defer c.mu.Unlock()
_, found := c.get(k)
if found {
c.mu.Unlock()
return fmt.Errorf("Item %s already exists", k)
}
c.set(k, x, d)
c.mu.Unlock()
return nil
}
@ -80,13 +81,13 @@ func (c *cache) Add(k string, x interface{}, d time.Duration) error {
// it does not.
func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
c.mu.Lock()
defer c.mu.Unlock()
_, found := c.get(k)
if !found {
c.mu.Unlock()
return fmt.Errorf("Item %s doesn't exist", k)
}
c.set(k, x, d)
c.mu.Unlock()
return nil
}
@ -94,9 +95,9 @@ func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
// the given key was found in the cache.
func (c *cache) Get(k string) (interface{}, bool) {
c.mu.Lock()
defer c.mu.Unlock()
return c.get(k)
x, found := c.get(k)
c.mu.Unlock()
return x, found
}
func (c *cache) get(k string) (interface{}, bool) {
@ -117,16 +118,16 @@ func (c *cache) get(k string) (interface{}, bool) {
// n. Passing a negative number will cause the item to be decremented.
func (c *cache) IncrementFloat(k string, n float64) error {
c.mu.Lock()
defer c.mu.Unlock()
v, found := c.Items[k]
if !found || v.Expired() {
c.mu.Unlock()
return fmt.Errorf("Item not found")
}
t := reflect.TypeOf(v.Object)
switch t.Kind() {
default:
c.mu.Unlock()
return fmt.Errorf("The value of %s is not an integer", k)
case reflect.Uint:
v.Object = v.Object.(uint) + uint(n)
@ -155,6 +156,7 @@ func (c *cache) IncrementFloat(k string, n float64) error {
case reflect.Float64:
v.Object = v.Object.(float64) + n
}
c.mu.Unlock()
return nil
}
@ -177,9 +179,8 @@ func (c *cache) Decrement(k string, n int64) error {
// Deletes an item from the cache. Does nothing if the item does not exist in the cache.
func (c *cache) Delete(k string) {
c.mu.Lock()
defer c.mu.Unlock()
c.delete(k)
c.mu.Unlock()
}
func (c *cache) delete(k string) {
@ -189,13 +190,12 @@ func (c *cache) delete(k string) {
// Deletes all expired items from the cache.
func (c *cache) DeleteExpired() {
c.mu.Lock()
defer c.mu.Unlock()
for k, v := range c.Items {
if v.Expired() {
c.delete(k)
}
}
c.mu.Unlock()
}
// Writes the cache's items (using Gob) to an io.Writer.
@ -262,9 +262,8 @@ func (c *cache) LoadFile(fname string) error {
// Deletes all items from the cache.
func (c *cache) Flush() {
c.mu.Lock()
defer c.mu.Unlock()
c.Items = map[string]*Item{}
c.mu.Unlock()
}
type janitor struct {

View File

@ -675,11 +675,11 @@ func BenchmarkCacheSetDelete(b *testing.B) {
func BenchmarkCacheSetDeleteSingleLock(b *testing.B) {
tc := New(0, 0)
tc.mu.Lock()
defer tc.mu.Unlock()
for i := 0; i < b.N; i++ {
tc.set("foo", "bar", 0)
tc.delete("foo")
}
tc.mu.Unlock()
}
func BenchmarkMapSetDelete(b *testing.B) {