In Golang channels are the recommended method for sharing data between threads, and I don’t refute this, but for simple single value data access a mutex is often more appropriate, simpler and more performant.
While building the args library, I needed a way to provide end users a thread safe way to retrieving the newest version of a config object. As I was very excited about my first practical application of channels, I initially implemented value access using golang channels.
Don’t miss understand, there is absolutely nothing wrong with using channels. but coming from a C++ background I found the resulting code to be overly complex for such a simple task.
Here is an example implementation from my benchmark project
Even if you ignore the house keeping chore of starting and stopping the goroutine, this is more complexity than I really wanted, especially when you compare it to an implementation that uses a mutex.
What is even more interesting, the mutex version is faster than the channel version. In a real world application the difference is negligible; the mutex version runs in 31 seconds, the channel version runs in 39 seconds. (See benchmark results below)
Since my initial implementation in args,
I’ve found at least one other use for singleton like access where a mutex was a
decidedly simpler solution. I’m experimenting with a reusable pattern where
any struct that wants thread safe member access can encapsulate a Locker
object. The result looks like this.
This example is super simple and doesn’t save typing but you can imagine wrapping more complex logic inside the anonymous function.
The implementation looks like the following
Here is the code for the benchmarks. And here are the results from my laptop.
make
go test -v ./...
=== RUN TestApi
Running Suite: Mutex Benchmark Suite
====================================
Random Seed: 1471284191
Will run 6 of 6 specs
• [MEASUREMENT]
Thread Safe Benchmarks
NotThreadSafe
Fastest Time: 29.627s
Slowest Time: 29.627s
Average Time: 29.627s ± 0.000s
------------------------------
• [MEASUREMENT]
Thread Safe Benchmarks
MutexWithDefer
Fastest Time: 31.188s
Slowest Time: 31.188s
Average Time: 31.188s ± 0.000s
------------------------------
• [MEASUREMENT]
Thread Safe Benchmarks
MutexWithoutDefer
Fastest Time: 32.350s
Slowest Time: 32.350s
Average Time: 32.350s ± 0.000s
------------------------------
• [MEASUREMENT]
Thread Safe Benchmarks
MutexWithLock
Fastest Time: 32.201s
Slowest Time: 32.201s
Average Time: 32.201s ± 0.000s
------------------------------
• [MEASUREMENT]
Thread Safe Benchmarks
RWMutexWithDefer
Fastest Time: 31.671s
Slowest Time: 31.671s
Average Time: 31.671s ± 0.000s
------------------------------
• [MEASUREMENT]
Thread Safe Benchmarks
ChannelSafety
Fastest Time: 39.555s
Slowest Time: 39.555s
Average Time: 39.555s ± 0.000s
------------------------------
Ran 6 of 6 Specs in 196.593 seconds
SUCCESS! -- 6 Passed | 0 Failed | 0 Pending | 0 Skipped --- PASS: TestApi (196.59s)
PASS
ok github.com/thrawn01/channel-mutex-defer-benchmarks 196.607s