Comment by ted_dunning
15 hours ago
The guardrails are channels.
If you have a mutex on a structure, linters such as are packaged into Goland will catch oversights quite effectively.
If you are using fancier concurrency structures, you should consider channels instead.
Channels are not for everything. Plenty of mutex cases cannot be rewritten as channels, or will be very unwieldy so. In fact, every large Go project I have seen uses mutex here or there.
Theoretically you can use channels to simulate a mutex, but I agree with you there are use cases where a mutex makes more sense. They are even used in the standard library, for instance to implement sync.Once.
But generally I would agree that if you need to code parallel execution, channels are a good way to do it, because you can avoid race conditions if you share data only over channels. The biggest problem is that a lot of people don't understand, that channels with a buffer larger than 1 are a sign of problems in the architecture.
There is a type of parallel programming with workers for specific functions, that always leads to performance issues. The problem is you need to right-guess the distribution of work, when you have to define the amount of workers for a specific function. At least one go routine for one request is a much better approach than function-specific workers.