/syncmap

A typed implementation of the Go sync.Map using code generation

Primary LanguageGo

syncmap

https://godoc.org/github.com/a8m/syncmap LICENSE Build Status Go Report Card

A typed implementation of the Go sync.Map using code generation.

Install

go get -u github.com/a8m/syncmap@master

Examples:

  1. Using CLI
$ syncmap -name IntMap "map[int]int"
$ syncmap -name RequestMap -pkg mypkg "map[string]*http.Request"

Or:

$ go run github.com/a8m/syncmap -name IntMap "map[int]int"
  1. Using go generate.

    • Add a directive with map definition:
      //go:generate go run github.com/a8m/syncmap -name WriterMap map[string]io.Writer
      
      //go:generate go run github.com/a8m/syncmap -name Requests map[string]*http.Request
    • Then, run go generate on this package.

    See testdata/gen.go for more examples.

How does it work?

syncmap didn't copy the code of sync/map.go and replace its identifiers. Instead, it reads the sync/map.go from your GOROOT, parses it into an *ast.File, and runs a few mutators that bring it to the desired state. Check the code for more information.

How can we make sure it will continue to work? - I'm running a daily CI test on TravisCI.

Benchmark

Benchmark tests were taken from the sync package.

BenchmarkLoadMostlyHits/*main.DeepCopyMap-8         	100000000	        15.1 ns/op
BenchmarkLoadMostlyHits/*main.RWMutexMap-8          	30000000	        54.4 ns/op
BenchmarkLoadMostlyHits/*sync.Map-8                 	100000000	        14.0 ns/op
BenchmarkLoadMostlyHits/*main.IntMap-8              	300000000	        5.65 ns/op <--

BenchmarkLoadMostlyMisses/*main.DeepCopyMap-8       	200000000	        10.2 ns/op
BenchmarkLoadMostlyMisses/*main.RWMutexMap-8        	30000000	        59.2 ns/op
BenchmarkLoadMostlyMisses/*sync.Map-8               	100000000	        11.3 ns/op
BenchmarkLoadMostlyMisses/*main.IntMap-8            	300000000	        4.05 ns/op <--

BenchmarkLoadOrStoreBalanced/*main.RWMutexMap-8     	 3000000	        400 ns/op
BenchmarkLoadOrStoreBalanced/*sync.Map-8            	 3000000	        400 ns/op
BenchmarkLoadOrStoreBalanced/*main.IntMap-8         	 5000000	        233 ns/op <--

BenchmarkLoadOrStoreUnique/*main.RWMutexMap-8       	 2000000	        744 ns/op
BenchmarkLoadOrStoreUnique/*sync.Map-8              	 2000000	        903 ns/op
BenchmarkLoadOrStoreUnique/*main.IntMap-8           	 3000000	        388 ns/op <--

BenchmarkLoadOrStoreCollision/*main.DeepCopyMap-8   	200000000	        7.29 ns/op
BenchmarkLoadOrStoreCollision/*main.RWMutexMap-8    	20000000	        97.5 ns/op
BenchmarkLoadOrStoreCollision/*sync.Map-8           	200000000	        9.11 ns/op
BenchmarkLoadOrStoreCollision/*main.IntMap-8        	500000000	        3.14 ns/op <--

BenchmarkRange/*main.DeepCopyMap-8                  	  500000	        4479 ns/op
BenchmarkRange/*main.RWMutexMap-8                   	   30000	        56834 ns/op
BenchmarkRange/*sync.Map-8                          	  300000	        4464 ns/op
BenchmarkRange/*main.IntMap-8                       	1000000000	        2.38 ns/op <--

BenchmarkAdversarialAlloc/*main.DeepCopyMap-8       	 2000000	        826 ns/op
BenchmarkAdversarialAlloc/*main.RWMutexMap-8        	20000000	        73.6 ns/op
BenchmarkAdversarialAlloc/*sync.Map-8               	 5000000	        303 ns/op
BenchmarkAdversarialAlloc/*main.IntMap-8            	10000000	        182 ns/op <--

BenchmarkAdversarialDelete/*main.DeepCopyMap-8      	10000000	        204 ns/op
BenchmarkAdversarialDelete/*main.RWMutexMap-8       	20000000	        78.3 ns/op
BenchmarkAdversarialDelete/*sync.Map-8              	20000000	        72.2 ns/op
BenchmarkAdversarialDelete/*main.IntMap-8           	100000000	        14.2 ns/op <--

Running benchmark with -benchmem

BenchmarkLoadMostlyHits/*main.DeepCopyMap-8         100000000	  12.7 ns/op	  7 B/op	  0 allocs/op
BenchmarkLoadMostlyHits/*main.RWMutexMap-8          30000000	  53.6 ns/op	  7 B/op	  0 allocs/op
BenchmarkLoadMostlyHits/*sync.Map-8                 100000000	  16.3 ns/op	  7 B/op	  0 allocs/op
BenchmarkLoadMostlyHits/*main.IntMap-8              200000000	  6.02 ns/op	  0 B/op	  0 allocs/op <--

BenchmarkLoadMostlyMisses/*main.DeepCopyMap-8       200000000	  7.99 ns/op	  7 B/op	  0 allocs/op
BenchmarkLoadMostlyMisses/*main.RWMutexMap-8        30000000	  52.6 ns/op	  7 B/op	  0 allocs/op
BenchmarkLoadMostlyMisses/*sync.Map-8               200000000	  8.87 ns/op	  7 B/op	  0 allocs/op
BenchmarkLoadMostlyMisses/*main.IntMap-8            1000000000	  2.88 ns/op	  0 B/op	  0 allocs/op <--

BenchmarkLoadOrStoreBalanced/*main.RWMutexMap-8     3000000	  357 ns/op	  71 B/op	  2 allocs/op
BenchmarkLoadOrStoreBalanced/*sync.Map-8            3000000	  417 ns/op	  70 B/op	  3 allocs/op
BenchmarkLoadOrStoreBalanced/*main.IntMap-8         5000000	  202 ns/op	  42 B/op	  1 allocs/op <--

BenchmarkLoadOrStoreUnique/*main.RWMutexMap-8       2000000	  648 ns/op	  178 B/op	  2 allocs/op
BenchmarkLoadOrStoreUnique/*sync.Map-8              2000000	  745 ns/op	  163 B/op	  4 allocs/op
BenchmarkLoadOrStoreUnique/*main.IntMap-8           3000000	  368 ns/op	  74 B/op	  2 allocs/op <--

BenchmarkLoadOrStoreCollision/*main.DeepCopyMap-8   300000000	  5.90 ns/op	  0 B/op	  0 allocs/op
BenchmarkLoadOrStoreCollision/*main.RWMutexMap-8    20000000	  94.5 ns/op	  0 B/op	  0 allocs/op
BenchmarkLoadOrStoreCollision/*sync.Map-8           200000000	  7.55 ns/op	  0 B/op	  0 allocs/op
BenchmarkLoadOrStoreCollision/*main.IntMap-8        1000000000	  2.68 ns/op	  0 B/op	  0 allocs/op <--

BenchmarkRange/*main.DeepCopyMap-8                  500000	  3376 ns/op	  0 B/op	  0 allocs/op
BenchmarkRange/*main.RWMutexMap-8                   30000	  56675 ns/op	  16384 B/op	  1 allocs/op
BenchmarkRange/*sync.Map-8                          500000	  3587 ns/op	  0 B/op	  0 allocs/op
BenchmarkRange/*main.IntMap-8                       2000000000	  1.75 ns/op	  0 B/op	  0 allocs/op <--

BenchmarkAdversarialAlloc/*main.DeepCopyMap-8       2000000	  761 ns/op	  535 B/op	  1 allocs/op
BenchmarkAdversarialAlloc/*main.RWMutexMap-8        20000000	  67.9 ns/op	  8 B/op	  1 allocs/op
BenchmarkAdversarialAlloc/*sync.Map-8               5000000	  264 ns/op	  51 B/op	  1 allocs/op
BenchmarkAdversarialAlloc/*main.IntMap-8            10000000	  176 ns/op	  28 B/op	  0 allocs/op <--

BenchmarkAdversarialDelete/*main.DeepCopyMap-8      10000000	  194 ns/op	  168 B/op	  1 allocs/op
BenchmarkAdversarialDelete/*main.RWMutexMap-8       20000000	  76.9 ns/op	  25 B/op	  1 allocs/op
BenchmarkAdversarialDelete/*sync.Map-8              20000000	  60.8 ns/op	  18 B/op	  1 allocs/op
BenchmarkAdversarialDelete/*main.IntMap-8           100000000	  13.1 ns/op	  0 B/op	  0 allocs/op <--

LICENSE

I am providing code in the repository to you under MIT license. Because this is my personal repository, the license you receive to my code is from me and not my employer (Facebook)