Skip to content

Instantly share code, notes, and snippets.

@TheHippo
Created August 15, 2015 02:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save TheHippo/75babf83556dc6f638a4 to your computer and use it in GitHub Desktop.
Save TheHippo/75babf83556dc6f638a4 to your computer and use it in GitHub Desktop.
Benchmarking Go Mutex overhead
package main
import (
"fmt"
"sync"
)
type unlocked struct {
i int
}
type locked struct {
i int
l sync.Mutex
}
func (c *unlocked) add() {
c.i++
}
func (c *locked) add() {
c.l.Lock()
defer c.l.Unlock()
c.i++
}
func main() {
fmt.Println("ok")
}
package main
import "testing"
func TestLocked_add(t *testing.T) {
c := locked{}
c.add()
if c.i != 1 {
t.Errorf("Expected 1 but got %d", c.i)
}
}
func BenchmarkLocked_add(t *testing.B) {
c := locked{}
for i := 0; i < t.N; i++ {
c.add()
}
if c.i != t.N {
t.Errorf("Expected %d, but got %d", t.N, c.i)
}
}
func TestUnlocked_add(t *testing.T) {
c := unlocked{}
c.add()
if c.i != 1 {
t.Errorf("Expected 1 but got %d", c.i)
}
}
func BenchmarkUnlocked_add(t *testing.B) {
c := unlocked{}
for i := 0; i < t.N; i++ {
c.add()
}
if c.i != t.N {
t.Errorf("Expected %d, but got %d", t.N, c.i)
}
}
$ go test -v -bench .
=== RUN TestLocked_add
--- PASS: TestLocked_add (0.00s)
=== RUN TestUnlocked_add
--- PASS: TestUnlocked_add (0.00s)
PASS
BenchmarkLocked_add 10000000 143 ns/op
BenchmarkUnlocked_add 1000000000 2.41 ns/op
ok _/home/hippo/test/mutex-bench 4.226s
@pascaldekloe
Copy link

go version go1.11.2 darwin/amd64

BenchmarkLocked_add-12      	30000000	        48.2 ns/op
BenchmarkUnlocked_add-12    	2000000000	         1.55 ns/op

Most of the slowdown comes from defer. When rewritten as

func (c *locked) add() {
	c.l.Lock()
	c.i++
	c.l.Unlock()
}

… then the numbers go down to:

BenchmarkLocked_add-12      	100000000	        19.4 ns/op
BenchmarkUnlocked_add-12    	2000000000	         1.55 ns/op

@psucodervn
Copy link

Defer's performance was improved from Go 1.14 https://golang.org/doc/go1.14#runtime

go version go1.16.4 darwin/amd64

Code

func (c *locked) addWithoutDefer() {
	c.l.Lock()
	c.i++
	c.l.Unlock()
}

func (c *locked) addWithDefer() {
	c.l.Lock()
	defer c.l.Unlock()
	c.i++
}

Result

goos: darwin
goarch: amd64
pkg: defer
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkLocked_addWithoutDefer
BenchmarkLocked_addWithoutDefer-12    	96066108	        12.30 ns/op
BenchmarkLocked_addWithDefer
BenchmarkLocked_addWithDefer-12       	92623209	        12.95 ns/op
BenchmarkUnlocked_add
BenchmarkUnlocked_add-12              	891768594	         1.322 ns/op

@btrvodka
Copy link

btrvodka commented Nov 3, 2023

go1.21.3 darwin/arm64


go test -v -bench .
=== RUN   TestLocked_add
--- PASS: TestLocked_add (0.00s)
=== RUN   TestUnlocked_add
--- PASS: TestUnlocked_add (0.00s)
goos: darwin
goarch: arm64
pkg: awesomeProject
BenchmarkLocked_add
BenchmarkLocked_add-12          87840225                13.77 ns/op
BenchmarkUnlocked_add
BenchmarkUnlocked_add-12        1000000000               0.3220 ns/op
PASS
ok      awesomeProject  2.228s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment