> Programming with threads is hard - it's hard to synchronize access to data structures without causing deadlocks; it's hard to reason about multiple threads accessing the same data, it's hard to choose the right locking granularity, etc.
That's a list of problems that are specific to mutable state that is shared among threads.
As the old saying goes, "If it hurts, don't do it."
We've had ways of doing multithreaded code that are easier to reason about for decades. They really do work quite well. Why people doggedly insist on pretending they don't exist is a perennial mystery to me. Even if your programming language wasn't kind enough to include a better concurrency model in its standard library, there are always third-party libraries.
I realize my experience isn't universal, but, personally, I've discovered that there's precisely one scenario where I ever need to resort to code that involves mutexes: When the business requirements and the performance profiler have conspired to kidnap my children and hold them for ransom.
"We've had ways of doing multithreaded code that are easier to reason about for decades. They really do work quite well. Why people doggedly insist on pretending they don't exist is a perennial mystery to me."
The real advantage to Go in a lot of ways was just starting over again with a couple decades more experience with multithreaded coding, and making the community default to a set of those more sane concurrency primitives. Nothing nominally stops you from doing the same thing in a number of other older threaded languages, but you're trying to bootstrap a new set of libraries from scratch, and that's not just a neutral operation, you are actively fought by the existing bulk of libraries for your existing language.
It's sort of weird that sometimes it's literally easier to start an entirely new language than fix an existing ecosystem and I can't say I've necessarily gotten my head wrapped around it, but observationally the evidence seems quite strong.
> We've had ways of doing multithreaded code that are easier to reason about for decades. They really do work quite well. Why people doggedly insist on pretending they don't exist is a perennial mystery to me.
Not a single one was mentioned during my CS undergrad; shared-memory threads were, many times. I think simple ignorance is the answer.
I think a simple love of complexity is also part of it. It's fun to do things that make you feel clever.
One experience I've had more often than I'd care to admit is diving into a multithreaded module with the intent of fixing a race condition bug, and finding that I could simultaneously remove the bug and realize a healthy performance improvement by making it single-threaded.
Which, for that matter, is another reason to be wary of mutexes and shared mutable data: Memory barriers do really impolite things to pipelines and caches in a modern CPU.
That's a list of problems that are specific to mutable state that is shared among threads.
As the old saying goes, "If it hurts, don't do it."
We've had ways of doing multithreaded code that are easier to reason about for decades. They really do work quite well. Why people doggedly insist on pretending they don't exist is a perennial mystery to me. Even if your programming language wasn't kind enough to include a better concurrency model in its standard library, there are always third-party libraries.
I realize my experience isn't universal, but, personally, I've discovered that there's precisely one scenario where I ever need to resort to code that involves mutexes: When the business requirements and the performance profiler have conspired to kidnap my children and hold them for ransom.