{"id":15914466,"url":"https://github.com/bbengfort/speedmap","last_synced_at":"2025-09-11T14:11:30.329Z","repository":{"id":69222769,"uuid":"140327865","full_name":"bbengfort/speedmap","owner":"bbengfort","description":"Benchmarks for concurrent access to key/value data structures","archived":false,"fork":false,"pushed_at":"2018-09-26T16:00:41.000Z","size":4812,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-08T17:45:33.374Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bbengfort.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-09T18:40:03.000Z","updated_at":"2018-09-27T08:54:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"d90c2483-e16c-4a32-af33-16fda241ff99","html_url":"https://github.com/bbengfort/speedmap","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbengfort%2Fspeedmap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbengfort%2Fspeedmap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbengfort%2Fspeedmap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbengfort%2Fspeedmap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bbengfort","download_url":"https://codeload.github.com/bbengfort/speedmap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246933356,"owners_count":20857052,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-06T17:03:10.839Z","updated_at":"2025-04-03T03:43:57.397Z","avatar_url":"https://github.com/bbengfort.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Speed Maps\n\n**Benchmarks for concurrent access to key/value data structures.**\n\n[![Build Status](https://travis-ci.com/bbengfort/speedmap.svg?branch=master)](https://travis-ci.com/bbengfort/speedmap)\n\nHere's the scenario: multiple clients are reading and writing values to different keys in a shared data structure. Each client is in their own go routine, unfortunately this means that a lock or a channel is required to synchronize accesses to the store. In this repository we explore different synchronization methods for concurrent access to the store to find out what is the most performant for various workloads.\n\nThere are two parts to each benchmark:\n\n1. A data structure that implements the `Store` interface.\n2. A workload that defines access patterns for increasing threads.\n\nThe store interface is pretty straight forward:\n\n```go\ntype Store interface {\n    Init() (err error)\n    Get(key string) (value []byte, err error)\n    Put(key string, value []byte) (err error)\n    Delete(key string) (err error)\n    GetOrCreate(key string, value []byte) (actual []byte, created bool)\n}\n```\n\nThe following stores have been implemented:\n\n1. Basic: wraps a `map[string][]byte` with a `sync.RWMutex` (baseline) and treats `GetOrCreate` as a write operation.\n2. Misframe: optimizes `GetOrCreate` as described in [Optimizing Concurrent Map Access in Go](https://misfra.me/optimizing-concurrent-map-access-in-go/).\n3. [`sync.Map`](https://golang.org/pkg/sync/#Map): the official concurrent map object in the sync package.\n4. Shard: map sharded into 32 different maps and accessed via hash, similar to the implementation of [concurrent-map](https://github.com/orcaman/concurrent-map). \n\n![Blast Benchmark](fixtures/figures/benchmark_blast_throughput.png)\n\n![Benchmark 50/50 Results](fixtures/figures/results.png)\n\n![Benchmark Write-Only Results](fixtures/figures/results-write.png)\n\n![Benchmark Read-Only Results](fixtures/figures/results-read.png)\n\n### Operation Benchmarks\n\nHere are the operational benchmarks for various store operations:\n\n![Operation Benchmarks](fixtures/figures/benchmark_operations.png)\n\nNote that the `Get` benchmark allocates keys from 0-255, then Gets the key in the benchmark by `i%256`; the timer is reset after storing the keys. Put just puts the key determined by `i` to the benchmark, which may exist already, since it seems that `i` is not necessarily unique across iterations (I can't explain it either). The `GetOrCreateEmpty` benchmark does not pre-allocate the database, but `GetOrCreateFull` does. The expectation is that the default key has to be inserted in the former case, but not in the latter. Finally the `Delete` benchmark does both a `Put` and a `Delete`, both have to be measured together, there is no way to isolate the `Delete` at the moment.\n\nHere are the raw benchmark numbers:\n\n```\ngoos: darwin\ngoarch: amd64\npkg: github.com/bbengfort/speedmap/store\nBenchmarkGet/basic-8                     \t 5000000\t       207 ns/op\nBenchmarkGet/misframe-8                  \t10000000\t       194 ns/op\nBenchmarkGet/sync_map-8                  \t10000000\t       172 ns/op\nBenchmarkGet/shard-8                     \t10000000\t       168 ns/op\n\nBenchmarkPut/basic-8                     \t10000000\t       236 ns/op\nBenchmarkPut/misframe-8                  \t10000000\t       225 ns/op\nBenchmarkPut/sync_map-8                  \t 5000000\t       312 ns/op\nBenchmarkPut/shard-8                     \t10000000\t       192 ns/op\n\nBenchmarkGetOrCreateEmpty/basic-8         \t 2000000\t       590 ns/op\nBenchmarkGetOrCreateEmpty/misframe-8      \t 2000000\t       582 ns/op\nBenchmarkGetOrCreateEmpty/sync_map-8      \t 1000000\t      1059 ns/op\nBenchmarkGetOrCreateEmpty/shard-8         \t 2000000\t       600 ns/op\n\nBenchmarkGetOrCreateFull/basic-8          \t10000000\t       238 ns/op\nBenchmarkGetOrCreateFull/misframe-8       \t10000000\t       187 ns/op\nBenchmarkGetOrCreateFull/sync_map-8       \t 5000000\t       267 ns/op\nBenchmarkGetOrCreateFull/shard-8          \t10000000\t       204 ns/op\n\nBenchmarkDelete/basic-8                   \t 5000000\t       302 ns/op\nBenchmarkDelete/misframe-8                \t 5000000\t       298 ns/op\nBenchmarkDelete/sync_map-8                \t 3000000\t       407 ns/op\nBenchmarkDelete/shard-8                   \t 5000000\t       237 ns/op\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbengfort%2Fspeedmap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbbengfort%2Fspeedmap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbengfort%2Fspeedmap/lists"}