I’ve been looking at the Go programming language recently, because (a) it’s started showing up a lot more in job descriptions, and (b) it combines the interesting attributes of both being compiled to machine language and being garbage-collected.
Unfortunately, it also falls victim to what I regard as an unfortunate fad amongst programming language designers in recent years: the decision that full, preemptive threading is something that programs don’t need and that some sort of ersatz (cooperative) concurrency is good enough.
Well, sorry, in my experience it’s just not. Maybe I’m atypically biased, because of my recent experience writing web crawlers, which have to parse pages as part of the job of finding new links to crawl. That’s a computationally complex task that in certain pathological cases can take indefinitely long. The solution is to run the parsing in a thread, and to kill that thread and proclaim the page unusable if it fails to parse in a reasonable amount of time.
This only works with true preemptive threading. The parsing is taking place in some third-party library that’s stuck in a loop someplace. I don’t want to recode the parsing library and clutter it up with dozens of yield statements. I shouldn’t have to recode it. But absent genuine threads, there is no alternative.
Maybe I’m being unfair here; maybe my experience with concurrency is highly unrepresentative. I don’t know, exactly. I can’t imagine I’m the only person who’s tried to make calls into a computationally complex library routine from a multithreaded program. So color me skeptical about the whole “ersatz threads are good enough” mindset.
I’ll note that C# has both full preemptive threading and the ability to be compiled down to machine code (by default, it’s just byte code, but there is what the C# world calls “ahead of time” compilation, which is just what I described). And C# is not a Microsoft-only thing; there’s Mono.