func (sm *StrMap) AsyncRange(f func(key string, value interface{}) bool) {
	for shard := range sm.mutexes {
		go func(shard int) {
			sm.mutexes[shard].RLock()
			for key, value := range sm.maps[shard] {
				if !f(key, value) {
					sm.mutexes[shard].RUnlock()
					return
				}
			}
			sm.mutexes[shard].RUnlock()
		}(shard)
	}
}
AsyncRange is exactly like ConcRange, but doesn't wait until all shards are
done. This is usually ok, although calls that appear to happen "sequentially"
on the same goroutine might get the before or after AsyncRange values, which
might be surprising behaviour. When that's not desirable, use ConcRange.
package shardedmap
import (
	"sync"
)
type StrMap struct {
	shardCount uint64  
	mutexes    []sync.RWMutex
	maps       []map[string]interface{}
}
func NewStrMap(shardCount int) *StrMap {
	if shardCount <= 0 {
		shardCount = defaultShards
	}
	sm := &StrMap{
		shardCount: uint64(shardCount),
		mutexes:    make([]sync.RWMutex, shardCount),
		maps:       make([]map[string]interface{}, shardCount),
	}
	for i := range sm.maps {
		sm.maps[i] = make(map[string]interface{})
	}
	return sm
}
func (sm *StrMap) pickShard(key string) uint64 {
	return memHashString(key) % sm.shardCount
}
func (sm *StrMap) Store(key string, value interface{}) {
	shard := sm.pickShard(key)
	sm.mutexes[shard].Lock()
	sm.maps[shard][key] = value
	sm.mutexes[shard].Unlock()
}
func (sm *StrMap) Load(key string) (interface{}, bool) {
	shard := sm.pickShard(key)
	sm.mutexes[shard].RLock()
	value, ok := sm.maps[shard][key]
	sm.mutexes[shard].RUnlock()
	return value, ok
}
func (sm *StrMap) LoadOrStore(key string, value interface{}) (actual interface{}, loaded bool) {
	shard := sm.pickShard(key)
	sm.mutexes[shard].RLock()
	if actual, loaded = sm.maps[shard][key]; loaded {
		sm.mutexes[shard].RUnlock()
		return
	}
	sm.mutexes[shard].RUnlock()
	sm.mutexes[shard].Lock()
	if actual, loaded = sm.maps[shard][key]; loaded {
		sm.mutexes[shard].Unlock()
		return
	}
	sm.maps[shard][key] = value
	sm.mutexes[shard].Unlock()
	return value, loaded
}
func (sm *StrMap) Delete(key string) {
	shard := sm.pickShard(key)
	sm.mutexes[shard].Lock()
	delete(sm.maps[shard], key)
	sm.mutexes[shard].Unlock()
}
func (sm *StrMap) Range(f func(key string, value interface{}) bool) {
	for shard := range sm.mutexes {
		sm.mutexes[shard].RLock()
		for key, value := range sm.maps[shard] {
			if !f(key, value) {
				sm.mutexes[shard].RUnlock()
				return
			}
		}
		sm.mutexes[shard].RUnlock()
	}
}
func (sm *StrMap) ConcRange(f func(key string, value interface{}) bool) {
	var wg sync.WaitGroup
	wg.Add(int(sm.shardCount))
	for shard := range sm.mutexes {
		go func(shard int) {
			sm.mutexes[shard].RLock()
			for key, value := range sm.maps[shard] {
				if !f(key, value) {
					sm.mutexes[shard].RUnlock()
					wg.Done()
					return
				}
			}
			sm.mutexes[shard].RUnlock()
			wg.Done()
		}(shard)
	}
	wg.Wait()
}