Comment by bwfan123

Comment by bwfan123 a day ago

35 replies

> Concurrency is tricky

The go language and its runtime is the only system I know that is able to handle concurrency with multicore cpus seamlessly within the language, using the CSP-like (goroutine/channel) formalism which is easy to reason with.

Python is a mess with the gil and async libraries that are hard to reason with. C,C++,Java etc need external libraries to implement threading which cant be reasoned with in the context of the language itself.

So, go is a perfect fit for the http server (or service) usecase and in my experience there is no parallel.

ashton314 a day ago

> So, go is a perfect fit for the http server (or service) usecase and in my experience there is no parallel.

Elixir handling 2 million websocket connections on a single machine back in 2015 would like to have a word.[1] This is largely thanks to the Erlang runtime it sits atop.

Having written some tricky Go (I implemented Raft for a class) and a lot of Elixir (professional development), it is my experience that Go's concurrency model works for a few cases but largely sucks in others and is way easier to write footguns in Go than it ought to be.

[1]: https://phoenixframework.org/blog/the-road-to-2-million-webs...

  • Fire-Dragon-DoL a day ago

    I worked in both Elixir and Go. I still think Elixir is best for concurrency.

    I recently realized that there is no easy way to "bubble up a goroutine error", and I wrote some code to make sure that was possible, and that's when I realize, as usual, that I'm rewriting part of the OTP library.

    The whole supervisor mechanism is so valuable for concurrency.

Jtsummers a day ago

> Java etc need external libraries to implement threading

Java does not need external libraries to implement threading, it's baked into the language and its standard libraries.

dehrmann a day ago

> Java etc need external libraries to implement threading which cant be reasoned with in the context of the language itself.

What do you mean by this for Java? The library is the runtime that ships with Java, and while they're OS threads under the hood, the abstraction isn't all that leaky, and it doesn't feel like they're actually outside the JVM.

Working with them can be a bit clunky, though.

  • gf000 a day ago

    Also, Java is one of the only languages with actually decent concurrent data structures right out of the box.

  • dboreham a day ago

    I think parent means they're (mostly) not supported via keywords. But you can use Kotlin and get that.

stouset a day ago

With all due respect, there are many languages in popular use that can do this, in many cases better than golang.

I believe it’s the only system you know. But it’s far from the only one.

  • antonchekhov a day ago

    > there are many languages in popular use that can do this, in many cases better than golang

    I'd love to see a list of these, with any references you can provide.

    • Jtsummers a day ago

      Erlang, Elixir, Ada, plenty of others. Erlang and Ada predate Go by several decades, too.

      You wanted sources, here's the chapter on tasks and synchronization in the Ada LRM: http://www.ada-auth.org/standards/22rm/html/RM-9.html

      For Erlang and Elixir, concurrent programming is pretty much their thing so grab any book or tutorial on them and you'll be introduced to how they handle it.

    • jose_zap a day ago

      Haskell would be one of them. It features transactional memory, which frees the programmer from having to think about explicitly locking.

  • ibic a day ago

    Please elaborate or give some examples to back your claim?

  • dismalaf a day ago

    There's not that many. C/C++ and Rust all map to OS threads and don't have CSP type concurrency built in.

    In Go's category, there's Java, Haskell, OCaml, Julia, Nim, Crystal, Pony...

    Dynamic languages are more likely to have green threads but aren't Go replacements.

    • Jtsummers a day ago

      > There's not that many.

      You list three that don't, and then you go on to list seven languages that do.

      Yes, not many languages support concurrency like Go does...

      • dismalaf a day ago

        And of those seven, how many are mainstream? A single one...

        So it's really Go vs. Java, or you can take a performance hit and use Erlang (valid choice for some tasks but not all), or take a chance on a novel paradigm/unsupported language.

    • jen20 a day ago

      Erlang (or Elixir) are absolutely Go replacements for the types of software where CSP is likely important.

      Source: spent the last few weeks at work replacing a Go program with an Elixir one instead.

      I'd use Go again (without question) but it is not a panacea. It should be the default choice for CLI utilities and many servers, but the notion that it is the only usable language with something approximating CSP is idiotic.

hintymad a day ago

Unless we consider JDK as external library. Speaking of library, Java's concurrency containers are truly powerful yet can be safely used by so many engineers. I don't think Go's ecosystem is even close.

hombre_fatal a day ago

> using the CSP-like (goroutine/channel) formalism which is easy to reason with

I thought it was a seldom mentioned fact in Go that CSP systems are impossible to reason about outside of toy projects so everyone uses mutexes and such for systemic coordination.

I'm not sure I've even seen channels in a production application used for anything more than stopping a goroutine, collecting workgroup results, or something equally localized.

  • kbolino a day ago

    There's also atomic operations (sync/atomic) and higher-level abstractions built on atomics and/or mutexes (sempahores, sync.Once, sync.WaitGroup/errgroup.Group, etc.). I've used these and seen them used by others.

    But yeah, the CSP model is mostly dead. I think the language authors' insistence that goroutines should not be addressable or even preemptible from user code makes this inevitable.

    Practical Go concurrency owes more to its green threads and colorless functions than its channels.

    • diarrhea a day ago

      > colorless

      Functions are colored: those taking context.Context and those who don't.

      But I agree, this is very faint coloring compared to async implementations. One is free to context.Background() liberally.

gf000 a day ago

Go is such a good fit for multi-core, especially that it is not even memory safe under data races..

  • kbolino a day ago

    It is rare to encounter this in practice, and it does get picked up by the race detector (which you have to consciously enable). But the language designers chose not to address it, so I think it's a valid criticism. [1]

    Once you know about it, though, it's easy to avoid. I do think, especially given that the CSP features of Go are downplayed nowadays, this should be addressed more prominently in the docs, with the more realistic solutions presented (atomics, mutexes).

    It could also potentially be addressed using 128-bit atomics, at least for strings and interfaces (whereas slices are too big, taking up 3 words). The idea of adding general 128-bit atomic support is on their radar [2] and there already exists a package for it [3], but I don't think strings or interfaces meet the alignment requirements.

    [1]: https://research.swtch.com/gorace

    [2]: https://github.com/golang/go/issues/61236

    [3]: https://pkg.go.dev/github.com/CAFxX/atomic128

dcrazy a day ago

Swift? JavaScript?

  • nothrabannosir a day ago

    JavaScript? How, web workers? JavaScript is M:1 threaded. You can’t use multiple cores without what basically amounts to user space ipc

    • mhink a day ago

      Not to dispute too strongly (since I haven't used this functionality myself), but Node.js does have support for true multithreading since v12: https://nodejs.org/dist/latest/docs/api/worker_threads.html. I'm not sure what you mean by "M:1 threaded" but I'm legitimately curious to understand more here, if you're willing to give more details.

      There are also runtimes like e.g. Hermes (used primarily by React Native), there's support for separating operations between the graphics thread and other threads.

      All that being said, I won't dispute OP's point about "handling concurrency [...] within the language"- multithreading and concurrency are baked into the Golang language in a more fundamental way than Javascript. But it's certainly worth pointing out that at least several of the major runtimes are capable of multithreading, out of the box.

      • nothrabannosir a day ago

        Yeah those are workers which require manual admin of memory shared / passed memory:

        > Within a worker thread, worker.getEnvironmentData() returns a clone of data passed to the spawning thread's worker.setEnvironmentData(). Every new Worker receives its own copy of the environment data automatically.

        M:1 threaded means that the user space threads are mapped onto a single kernel thread. Go is M:N threaded: goroutines can be arbitrarily scheduled across various underlying OS threads. Its primitives (goroutines and channels) make both concurrency and parallelism notably simpler than most languages.

        > But it's certainly worth pointing out that at least several of the major runtimes are capable of multithreading, out of the box.

        I’d personally disagree in this context. Almost every language has pthread-style cro-magnon concurrency primitives. The context for this thread is precisely how go differs from regular threading interfaces. Quoting gp:

        > The go language and its runtime is the only system I know that is able to handle concurrency with multicore cpus seamlessly within the language, using the CSP-like (goroutine/channel) formalism which is easy to reason with.

        Yes other languages have threading, but in go both concurrency and parallelism are easier than most.

        (But not erlang :) )

      • tom_m 17 hours ago

        Even the node author came out and said the concurrency design there was wrong and switched to golang. Libuv is cool and all, but doesn't handle everything and you still have a bottleneck, poor isolation, and the single threaded event loop to deal with. Back pressure in node becomes a real thing and the whole thing becomes very painful and obvious at scale.

        Granted, many people don't ever need to handle that kind of throughput. It depends on the app and the load put on to it. So many people don't realize. Which is fine! If it works it works. But if you do fall into the need of concurrency, yea, you probably don't want to be using node - even the newer versions. You certainly could do worse than golang. It's good we have some choices out there.

        The other thing I always say is the choice in languages and technology is not for one person. It's for the software and team at hand. I often choose languages, frameworks, and tools specifically because of the team that's charged with building and maintaining. If you can make them successful because a language gives them type safety or memory safety that rust offers or a good tool chain, whatever it is that the team needs - that's really good. In fact, it could well be the difference between a successful business and an unsuccessful one. No one really cares how magical the software is if the company goes under and no one uses the software.

    • [removed] a day ago
      [deleted]