-
If you are coordinating goroutines or tracking a value as it is transformed by a series of goroutines, use channels.
-
If you are sharing access to a field in a struct, use mutexes.
-
If you discover a critical performance issue when using channels, and you cannot find any other way to fix the issue, modify your code to use a mutex.
Another issue is that mutexes in Go aren’t reentrant. If a goroutine tries to acquire the same lock twice, it deadlocks, waiting for itself to release the lock. This is different from languages like Java, where locks are reentrant.
Nonreentrant locks make it tricky to acquire a lock in a function that calls itself recursively. You must release the lock before the recursive function call.
In general, be careful when holding a lock while making a function call, because you don’t know what locks are going to be acquired in those calls. If your function calls another function that tries to acquire the same mutex lock, the goroutine deadlocks.