If you modify the code to release the lock before sleeping...
func (c *Counter) add(ch chan int) {
c.Lock()
tmp := c.Num
c.Unlock()
tmp += 1
time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
c.Lock()
c.Num = tmp
c.Unlock()
ch <- 1
}
...and reacquiring it after, it still finishes in 10ms on my machine, as you'd expect. As you can see, the problem isn't so much that locks are inherently slow in Go, but rather the mutex, as the acqusition function name implies, is doing what it is supposed to do: Lock. What is true is that you have to be careful to use them properly.