Решение на ExpireMap от Красимир Стойков

Обратно към всички решения

Към профила на Красимир Стойков

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 20 успешни тест(а)
  • 5 неуспешни тест(а)

Код

package main
import (
"errors"
"strconv"
"strings"
"sync"
"time"
)
type ExpireMap struct {
values map[string]interface{}
expirers map[string]time.Time
ch chan string
sync.RWMutex
}
func NewExpireMap() *ExpireMap {
return &ExpireMap{make(map[string]interface{}), make(map[string]time.Time), make(chan string, 1), *new(sync.RWMutex)}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.Lock()
_, exist := em.values[key]
expireTime := time.Now().Add(expire)
em.values[key] = value
em.expirers[key] = expireTime
em.Unlock()
if !exist {
go func(key string) {
for {
em.Lock()
_, check := em.values[key] //just to be sure
if !check {
em.Unlock()
return
}
if time.Now().After(em.expirers[key]) {
delete(em.values, key)
delete(em.expirers, key)
if len(em.ch) == cap(em.ch) {
newCh := make(chan string, 2*cap(em.ch))
for i := 0; i < cap(em.ch); i++ {
newCh <- <-em.ch
}
em.ch = newCh
}
em.ch <- key
em.Unlock()
return
} else {
em.Unlock()
}
}
}(key)
}
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.RLock()
value, err := em.values[key]
em.RUnlock()
return value, err
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
em.RLock()
value, err := em.values[key].(int)
em.RUnlock()
return value, err
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
em.RLock()
value, err := em.values[key].(float64)
em.RUnlock()
return value, err
}
func (em *ExpireMap) GetString(key string) (string, bool) {
em.RLock()
value, err := em.values[key].(string)
em.RUnlock()
return value, err
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
em.RLock()
value, err := em.values[key].(bool)
em.RUnlock()
return value, err
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.RLock()
value, err := em.expirers[key]
em.RUnlock()
return value, err
}
func (em *ExpireMap) Delete(key string) {
em.Lock()
delete(em.values, key)
delete(em.expirers, key)
em.Unlock()
}
func (em *ExpireMap) Contains(key string) bool {
em.RLock()
_, exist := em.expirers[key] //faster than map with interface{}?
em.RUnlock()
return exist
}
func (em *ExpireMap) Size() int {
return len(em.values)
}
func (em *ExpireMap) add(key string, n int) error {
em.Lock()
valueI, isInt := em.values[key].(int)
if isInt {
valueI += n
em.values[key] = valueI
em.Unlock()
return nil
}
valueS, isString := em.values[key].(string)
if isString {
num, err := strconv.Atoi(valueS)
if err == nil {
num += n
em.values[key] = strconv.Itoa(num)
em.Unlock()
return nil
}
}
em.Unlock()
return errors.New("Doesn't exist or not an incrementable type")
}
func (em *ExpireMap) Increment(key string) error {
return em.add(key, 1)
}
func (em *ExpireMap) Decrement(key string) error {
return em.add(key, -1)
}
func (em *ExpireMap) stringFunc(key string, f func(string) string) error {
em.Lock()
value, isString := em.values[key].(string)
if isString {
value = f(value)
em.values[key] = value
em.Unlock()
return nil
}
em.Unlock()
return errors.New("Doesn't exist or not a string")
}
func (em *ExpireMap) ToUpper(key string) error {
return em.stringFunc(key, strings.ToUpper)
}
func (em *ExpireMap) ToLower(key string) error {
return em.stringFunc(key, strings.ToLower)
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.ch
}
func (em *ExpireMap) Cleanup() {
em.Lock()
em.values = make(map[string]interface{})
em.expirers = make(map[string]time.Time)
em.ch = make(chan string)
em.Unlock()
}
func (em *ExpireMap) Destroy() {
go func() {
em.Lock()
em.values = nil
em.expirers = nil
close(em.ch)
}()
}

Лог от изпълнението

PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.050s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.073s
panic: test timed out

goroutine 15 [running]:
testing.alarm()
	/usr/local/lib/go/src/pkg/testing/testing.go:533 +0x44
created by time.goFunc
	/usr/local/lib/go/src/pkg/time/sleep.go:122 +0x45

goroutine 1 [chan receive]:
testing.RunTests(0x8148570, 0x81c2ba0, 0x19, 0x19, 0x1, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:434 +0x69f
testing.Main(0x8148570, 0x81c2ba0, 0x19, 0x19, 0x81c5600, ...)
	/usr/local/lib/go/src/pkg/testing/testing.go:365 +0x69
main.main()
	_/tmp/d20141204-6466-4nnx65/_test/_testmain.go:91 +0x81

goroutine 4 [sleep]:
time.Sleep(0x3c336080, 0x0)
	/usr/local/lib/go/src/pkg/runtime/ztime_linux_386.c:19 +0x3a
_/tmp/d20141204-6466-4nnx65.TestSizes(0x183611e0)
	/tmp/d20141204-6466-4nnx65/solution_test.go:111 +0x3d8
testing.tRunner(0x183611e0, 0x81c2bb8)
	/usr/local/lib/go/src/pkg/testing/testing.go:353 +0x87
created by testing.RunTests
	/usr/local/lib/go/src/pkg/testing/testing.go:433 +0x684

goroutine 5 [semacquire]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x18300308, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 6 [semacquire]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x18300330, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 7 [semacquire]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x18300358, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 8 [semacquire]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x18300380, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 9 [semacquire]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x183003a8, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 10 [semacquire]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x183003d0, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 11 [semacquire]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x183003f8, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 12 [semacquire]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x18300420, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 13 [running]:
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab

goroutine 14 [runnable]:
sync.runtime_Semacquire(0x18348610)
	/usr/local/lib/go/src/pkg/runtime/zsema_linux_386.c:165 +0x32
sync.(*Mutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/mutex.go:66 +0xb6
sync.(*RWMutex).Lock(0x1834860c)
	/usr/local/lib/go/src/pkg/sync/rwmutex.go:78 +0x29
_/tmp/d20141204-6466-4nnx65.func·001(0x18300470, 0x5)
	/tmp/d20141204-6466-4nnx65/solution.go:31 +0x36
created by _/tmp/d20141204-6466-4nnx65.(*ExpireMap).Set
	/tmp/d20141204-6466-4nnx65/solution.go:54 +0x1ab
exit status 2
FAIL	_/tmp/d20141204-6466-4nnx65	1.013s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.122s
--- FAIL: TestGettingExpiredValues-2 (0.16 seconds)
	solution_test.go:168: Getting expired key did not return error
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-4nnx65	0.172s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.076s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.156s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.013s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.140s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.067s
--- FAIL: TestExpiredChanWhenNoOneIsReading-2 (0.06 seconds)
	solution_test.go:554: Wrong key expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-4nnx65	0.073s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.112s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.132s
*** Test killed: ran too long (1m1s).
FAIL	_/tmp/d20141204-6466-4nnx65	61.007s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.012s
--- FAIL: TestMultipleKeysWithTheSameExpireTime-2 (0.29 seconds)
	solution_test.go:895: Key same-time-key-4 did not expire
	solution_test.go:900: Key same-time-key-4 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-5 did not expire
	solution_test.go:900: Key same-time-key-5 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-6 did not expire
	solution_test.go:900: Key same-time-key-6 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-7 did not expire
	solution_test.go:900: Key same-time-key-7 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-8 did not expire
	solution_test.go:900: Key same-time-key-8 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-9 did not expire
	solution_test.go:900: Key same-time-key-9 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-10 did not expire
	solution_test.go:900: Key same-time-key-10 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-11 did not expire
	solution_test.go:900: Key same-time-key-11 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-12 did not expire
	solution_test.go:900: Key same-time-key-12 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-13 did not expire
	solution_test.go:900: Key same-time-key-13 had expire time even though it has expired
	solution_test.go:895: Key same-time-key-14 did not expire
	solution_test.go:900: Key same-time-key-14 had expire time even though it has expired
FAIL
exit status 1
FAIL	_/tmp/d20141204-6466-4nnx65	0.304s
PASS
ok  	_/tmp/d20141204-6466-4nnx65	0.015s

История (2 версии и 1 коментар)

Красимир обнови решението на 18.11.2014 16:26 (преди над 3 години)

+package main
+
+import (
+ "errors"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+type ExpireMap struct {
+ values map[string]interface{}
+ expirers map[string]time.Time
+ ch chan string
+ sync.RWMutex
+}
+
+func NewExpireMap() *ExpireMap {
+ return &ExpireMap{make(map[string]interface{}), make(map[string]time.Time), make(chan string, 1000), *new(sync.RWMutex)}
+}
+func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
+ em.Lock()
+ _, exist := em.values[key]
+ expireTime := time.Now().Add(expire)
+ em.values[key] = value
+ em.expirers[key] = expireTime
+ em.Unlock()
+ if !exist {
+ go func(key string) {
+ for {
+ em.Lock()
+ if time.Now().After(em.expirers[key]) {
+ delete(em.values, key)
+ delete(em.expirers, key)
+ if len(em.ch) == cap(em.ch) {
+ newCh := make(chan string, 2*cap(em.ch))
+ for i := 0; i < cap(em.ch); i++ {
+ newCh <- <-em.ch
+ }
+ em.ch = newCh
+ }
+ em.ch <- key
+ em.Unlock()
+ return
+ } else {
+ em.Unlock()
+ }
+ }
+ }(key)
+ }
+}
+func (em *ExpireMap) Get(key string) (interface{}, bool) {
+ em.RLock()
+ value, err := em.values[key]
+ em.RUnlock()
+ return value, err
+}
+func (em *ExpireMap) GetInt(key string) (int, bool) {
+ em.RLock()
+ value, err := em.values[key].(int)
+ em.RUnlock()
+ return value, err
+}
+func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
+ em.RLock()
+ value, err := em.values[key].(float64)
+ em.RUnlock()
+ return value, err
+}
+func (em *ExpireMap) GetString(key string) (string, bool) {
+ em.RLock()
+ value, err := em.values[key].(string)
+ em.RUnlock()
+ return value, err
+}
+func (em *ExpireMap) GetBool(key string) (bool, bool) {
+ em.RLock()
+ value, err := em.values[key].(bool)
+ em.RUnlock()
+ return value, err
+}
+func (em *ExpireMap) Expires(key string) (time.Time, bool) {
+ em.RLock()
+ value, err := em.expirers[key]
+ em.RUnlock()
+ return value, err
+}
+func (em *ExpireMap) Delete(key string) {
+ em.Lock()
+ delete(em.values, key)
+ delete(em.expirers, key)
+ em.Unlock()
+}
+func (em *ExpireMap) Contains(key string) bool {
+ em.RLock()
+ _, exist := em.expirers[key] //faster than map with interface{}?
+ em.RUnlock()
+ return exist
+}
+func (em *ExpireMap) Size() int {
+ return len(em.values)
+}
+func (em *ExpireMap) add(key string, n int) error {
+ em.Lock()
+ valueI, isInt := em.values[key].(int)
+ if isInt {
+ valueI += n
+ em.values[key] = valueI
+ em.Unlock()
+ return nil
+ }
+ valueS, isString := em.values[key].(string)
+ if isString {
+ num, err := strconv.Atoi(valueS)
+ if err == nil {
+ num += n
+ em.values[key] = strconv.Itoa(num)
+ em.Unlock()
+ return nil
+ }
+ }
+ em.Unlock()
+ return errors.New("Doesn't exist or not an incrementable type")
+}
+func (em *ExpireMap) Increment(key string) error {
+ return em.add(key, 1)
+}
+func (em *ExpireMap) Decrement(key string) error {
+ return em.add(key, -1)
+}
+func (em *ExpireMap) stringFunc(key string, f func(string) string) error {
+ em.Lock()
+ value, isString := em.values[key].(string)
+ if isString {
+ value = f(value)
+ em.values[key] = value
+ em.Unlock()
+ return nil
+ }
+ em.Unlock()
+ return errors.New("Doesn't exist or not a string")
+}
+func (em *ExpireMap) ToUpper(key string) error {
+ return em.stringFunc(key, strings.ToUpper)
+}
+func (em *ExpireMap) ToLower(key string) error {
+ return em.stringFunc(key, strings.ToLower)
+}
+func (em *ExpireMap) ExpiredChan() <-chan string {
+ return em.ch
+}
+func (em *ExpireMap) Cleanup() {
+ em.Lock()
+ em.values = make(map[string]interface{})
+ em.expirers = make(map[string]time.Time)
+ em.ch = make(chan string)
+ em.Unlock()
+}
+func (em *ExpireMap) Destroy() {
+ go func() {
+ em.Lock()
+ em.values = nil
+ em.expirers = nil
+ close(em.ch)
+ }()
+}

Красимир обнови решението на 18.11.2014 16:54 (преди над 3 години)

package main
import (
"errors"
"strconv"
"strings"
"sync"
"time"
)
type ExpireMap struct {
values map[string]interface{}
expirers map[string]time.Time
ch chan string
sync.RWMutex
}
func NewExpireMap() *ExpireMap {
- return &ExpireMap{make(map[string]interface{}), make(map[string]time.Time), make(chan string, 1000), *new(sync.RWMutex)}
+ return &ExpireMap{make(map[string]interface{}), make(map[string]time.Time), make(chan string, 1), *new(sync.RWMutex)}
}
func (em *ExpireMap) Set(key string, value interface{}, expire time.Duration) {
em.Lock()
_, exist := em.values[key]
expireTime := time.Now().Add(expire)
em.values[key] = value
em.expirers[key] = expireTime
em.Unlock()
if !exist {
go func(key string) {
for {
em.Lock()
+ _, check := em.values[key] //just to be sure
+ if !check {
+ em.Unlock()
+ return
+ }
if time.Now().After(em.expirers[key]) {
delete(em.values, key)
delete(em.expirers, key)
if len(em.ch) == cap(em.ch) {
newCh := make(chan string, 2*cap(em.ch))
for i := 0; i < cap(em.ch); i++ {
newCh <- <-em.ch
}
em.ch = newCh
}
em.ch <- key
em.Unlock()
return
} else {
em.Unlock()
}
}
}(key)
}
}
func (em *ExpireMap) Get(key string) (interface{}, bool) {
em.RLock()
value, err := em.values[key]
em.RUnlock()
return value, err
}
func (em *ExpireMap) GetInt(key string) (int, bool) {
em.RLock()
value, err := em.values[key].(int)
em.RUnlock()
return value, err
}
func (em *ExpireMap) GetFloat64(key string) (float64, bool) {
em.RLock()
value, err := em.values[key].(float64)
em.RUnlock()
return value, err
}
func (em *ExpireMap) GetString(key string) (string, bool) {
em.RLock()
value, err := em.values[key].(string)
em.RUnlock()
return value, err
}
func (em *ExpireMap) GetBool(key string) (bool, bool) {
em.RLock()
value, err := em.values[key].(bool)
em.RUnlock()
return value, err
}
func (em *ExpireMap) Expires(key string) (time.Time, bool) {
em.RLock()
value, err := em.expirers[key]
em.RUnlock()
return value, err
}
func (em *ExpireMap) Delete(key string) {
em.Lock()
delete(em.values, key)
delete(em.expirers, key)
em.Unlock()
}
func (em *ExpireMap) Contains(key string) bool {
em.RLock()
_, exist := em.expirers[key] //faster than map with interface{}?
em.RUnlock()
return exist
}
func (em *ExpireMap) Size() int {
return len(em.values)
}
func (em *ExpireMap) add(key string, n int) error {
em.Lock()
valueI, isInt := em.values[key].(int)
if isInt {
valueI += n
em.values[key] = valueI
em.Unlock()
return nil
}
valueS, isString := em.values[key].(string)
if isString {
num, err := strconv.Atoi(valueS)
if err == nil {
num += n
em.values[key] = strconv.Itoa(num)
em.Unlock()
return nil
}
}
em.Unlock()
return errors.New("Doesn't exist or not an incrementable type")
}
func (em *ExpireMap) Increment(key string) error {
return em.add(key, 1)
}
func (em *ExpireMap) Decrement(key string) error {
return em.add(key, -1)
}
func (em *ExpireMap) stringFunc(key string, f func(string) string) error {
em.Lock()
value, isString := em.values[key].(string)
if isString {
value = f(value)
em.values[key] = value
em.Unlock()
return nil
}
em.Unlock()
return errors.New("Doesn't exist or not a string")
}
func (em *ExpireMap) ToUpper(key string) error {
return em.stringFunc(key, strings.ToUpper)
}
func (em *ExpireMap) ToLower(key string) error {
return em.stringFunc(key, strings.ToLower)
}
func (em *ExpireMap) ExpiredChan() <-chan string {
return em.ch
}
func (em *ExpireMap) Cleanup() {
em.Lock()
em.values = make(map[string]interface{})
em.expirers = make(map[string]time.Time)
em.ch = make(chan string)
em.Unlock()
}
func (em *ExpireMap) Destroy() {
go func() {
em.Lock()
em.values = nil
em.expirers = nil
close(em.ch)
}()
}

Ще е възможно ли преди да ми тествате решението да увеличите началния размер на канала ми от 1 на нещо по-голямо от сорта на 1000, защото в бързината не съм забелязал, че последно съм си тествал с размер 1 и така втората ми версия има вероятнист да трие ключовере с някакво забавяне, защото губи време да задели памет за по-голям буфер...