Created
April 27, 2020 11:58
-
-
Save mstoykov/c709d4dd8060bbaa3bd20b0eecc4c29a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "math/rand" | |
| "sort" | |
| "strings" | |
| "testing" | |
| "time" | |
| ) | |
| const ( | |
| keyLen = 5 | |
| valLen = 20 | |
| ) | |
| func gen(length int) string { | |
| var s string | |
| for i := 0; i < length; i++ { | |
| s += string(rand.Int31n(126-48) + int32(48)) | |
| } | |
| return s | |
| } | |
| type Item struct { | |
| Key string | |
| Val string | |
| } | |
| /******************** | |
| * A typical key/value storage, once as map[string]string, once | |
| * as []*Item{string,string}. | |
| */ | |
| func populateKV(theArr []Item, theMap map[string]string) string { | |
| var query string | |
| var k, v string | |
| rand.Seed(time.Now().UnixNano()) | |
| // pick one of the items at random to be the lookup key | |
| queryI := rand.Intn(len(theArr)) | |
| for i := 0; i < len(theArr); i++ { | |
| k = gen(keyLen) | |
| v = gen(valLen) | |
| theMap[k] = v | |
| theArr[i] = Item{Key: k, Val: v} | |
| if i == queryI { | |
| query = k | |
| } | |
| } | |
| sort.Slice(theArr, func(i, j int) bool { return strings.Compare(theArr[i].Key, theArr[j].Key) > 0 }) | |
| return query | |
| } | |
| func BenchmarkKVItemSlice(b *testing.B) { | |
| for _, numItems := range []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 50} { | |
| numItems := numItems | |
| b.Run(fmt.Sprintf("%d", numItems), func(b *testing.B) { | |
| theMap := make(map[string]string) | |
| theArr := make([]Item, numItems) | |
| q := populateKV(theArr, theMap) | |
| b.ResetTimer() | |
| for n := 0; n < b.N; n++ { | |
| i, j := 0, len(theArr) | |
| for i < j { | |
| h := int(uint(i+j) >> 1) // avoid overflow when computing h | |
| // i ≤ h < j | |
| if theArr[h].Key > q { | |
| i = h + 1 // preserves f(i-1) == false | |
| } else { | |
| j = h // preserves f(j) == true | |
| } | |
| } | |
| if theArr[i].Key != q { | |
| b.Fail() | |
| } | |
| } | |
| }) | |
| } | |
| } | |
| func BenchmarkKVStringMap(b *testing.B) { | |
| for _, numItems := range []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 50} { | |
| numItems := numItems | |
| b.Run(fmt.Sprintf("%d", numItems), func(b *testing.B) { | |
| var found bool | |
| theMap := make(map[string]string) | |
| theArr := make([]Item, numItems) | |
| q := populateKV(theArr, theMap) | |
| b.ResetTimer() | |
| for i := 0; i < b.N; i++ { | |
| if theMap[q] != "" { | |
| found = true | |
| } | |
| } | |
| if !found { | |
| b.Fail() | |
| } | |
| }) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Seems like the Slice one scale ... "better" but actually the map is pretty consistent once we are above 10 items and actually faster - it is also somehow faster anywhere else but around 4-8 number of items ...