hashmap icon indicating copy to clipboard operation
hashmap copied to clipboard

the speed for set is really really really low

Open liujiangwei opened this issue 5 years ago • 5 comments

the size bigger,the speed lower!!!!

for different keys

1000 = 1ms

10000 = 200ms

100000 = 129000ms

only suit for small size map

liujiangwei avatar Aug 14 '20 02:08 liujiangwei

修改下即可 func (m *HashMap) indexElement(hashedKey uintptr) (data *hashMapData, item *ListElement) { data = m.mapData() if data == nil { return nil, nil }
index := hashedKey >> data.keyshifts ptr := (unsafe.Pointer)(unsafe.Pointer(uintptr(data.data) + indexintSizeBytes)) item = (*ListElement)(atomic.LoadPointer(ptr)) // ---------------------------------------------------------------- for (item == nil || hashedKey < item.keyHash) && index > 0 { index-- ptr = (unsafe.Pointer)(unsafe.Pointer(uintptr(data.data) + indexintSizeBytes)) item = (*ListElement)(atomic.LoadPointer(ptr)) }
// -----------------------------------------------------------------------

    return data, item

}

lzf575 avatar Apr 09 '21 03:04 lzf575

The proper fix would be an improvement of the search algorithm in List.search().

cornelk avatar Aug 09 '22 18:08 cornelk

What about a skiplist?

photoszzt avatar Aug 20 '22 21:08 photoszzt

I can confirm this. I benchmark with around 1M keys in https://github.com/s0lesurviv0r/go-concurrent-map-bench and I haven't been able to add this library as it timed out (10 minutes)

s0lesurviv0r avatar Dec 09 '22 09:12 s0lesurviv0r

try the patch

diff --git a/hashmap.go b/hashmap.go
index 3bf83c1..3594560 100644
--- a/hashmap.go
+++ b/hashmap.go
@@ -170,7 +170,7 @@ func (m *Map[Key, Value]) Set(key Key, value Value) {
 
        for {
                store := m.store.Load()
-               searchStart := store.item(hash)
+               searchStart := store.itemOrPreNotNull(hash)
 
                element, added := m.linkedList.AddOrUpdate(searchStart, hash, key, value)
                if !added {
diff --git a/store.go b/store.go
index 8fc1d59..7fc6a2d 100644
--- a/store.go
+++ b/store.go
@@ -20,6 +20,23 @@ func (s *store[Key, Value]) item(hashedKey uintptr) *ListElement[Key, Value] {
        return item
 }
 
+func (s *store[Key, Value]) itemOrPreNotNull(hashedKey uintptr) *ListElement[Key, Value] {
+       index := hashedKey >> s.keyShifts
+       ptr := (*unsafe.Pointer)(unsafe.Pointer(uintptr(s.array) + index*intSizeBytes))
+       item := (*ListElement[Key, Value])(atomic.LoadPointer(ptr))
+       // 若index的item为空时或新增的item的hash值小于该index的hash值时,
+       // 则会从表头开始检索,这样导致性能太慢,修改为从前一个非nil的index开始检索
+       // ---------------------------------------------------------------------------
+       // If the item at the index position is empty or the hashedKey is less than the hash value of the item,
+       // It will be retrieved from the header of the table, which will lead to too slow performance. It will be modified to retrieve from the previous non-nil index
+       for (item == nil || hashedKey < item.keyHash) && index > 0 {
+               index--
+               ptr = (*unsafe.Pointer)(unsafe.Pointer(uintptr(s.array) + index*intSizeBytes))
+               item = (*ListElement[Key, Value])(atomic.LoadPointer(ptr))
+       }
+       return item
+}
+
 // adds an item to the index if needed and returns the new item counter if it changed, otherwise 0.
 func (s *store[Key, Value]) addItem(item *ListElement[Key, Value]) uintptr {
        index := item.keyHash >> s.keyShifts

lzf575 avatar Jan 05 '24 01:01 lzf575