Threads for lukesteensen

  1. 2

    This seems very similar to the RUM conjecture.

    1. 1

      Really interesting article, but there was one tidbit at the end that confused me:

      … goroutines are Go’s best feature (and incidentally one of the ways Go is better than Rust for some applications)

      Is this implying that go’s M:N threading makes it a fundamentally more “correct” choice for certain applications? My understanding is that goroutines, while more efficient than threads in Rust, are still subject to the same resource exhaustion issues. For example, you might be able to get away with 1M goroutines as opposed to 100k Rust threads, but that doesn’t mean you never have to think about the number of goroutines.

      1. 3

        M:N threading can be “more convenient”.

        1. 3

          At the risk of repeating the basics: Using a full-size stack for every continuation when you have large numbers of almost-identical continuations is clearly horribly inefficient. E.g. imagine you have a basic CRUD web backend that just takes an id, loads the relevant object from some datastore, transforms it into JSON and returns it to the client. While the request is being processed by the datastore, the app needs to store enough data to, when it receives the response from the datastore, know which client to send the rendered JSON back to. That only actually means storing two small integers - the (socket) id of the datastore connection and the id of the web connection - potentially as little as 8 bytes (or even 4 bytes on a 32-bit machine) in total. But in traditional one-thread-per-request architectures each request would have its own thread meaning its own stack meaning at an absolute minimum one 4k physical page of memory. Whereas if you’re just storing a continuation for the datastore connection that’s potentially just simple data and the language runtime could potentially store the continuations for many requests in the same memory page.

          So there’s at least a theoretical argument that non-native threads can be more efficient. AIUI (and I could easily be wrong here) M:N green threads (rather than full continuations) mostly makes sense in the context of segmented stacks (i.e. variable stack sizes). Both Rust and Go started with segmented stacks and green threads and eventually abandoned the segmented stacks; Rust abandoned the green threads at least partly on the grounds that they no longer made sense. I would think the same reasoning may apply to go, at least if it’s storing a full stack for each goroutine (maybe it isn’t?) - that now that segmented stacks have been abandoned there’s no value in M:N. But I could easily be missing something.

          1. 2

            That is an interesting question. The best information I could find in a quick google search was that Go 1.2 increased the minimum stack size of a goroutine from 4KB to 8KB in 1.2. It also looks like Rust allows you to set the stack size of a new thread. I’m not knowledgable enough to know exactly what this means, but it’s certainly interesting.

          2. 1

            Is 100k OS threads an actual reasonable number? Lightweight threads seem better for a web server, but spawning a “thread” per request, but I could be wrong.

            1. 1

              I was thinking of this comment thread, which has a lot of good discussion on the topic. This comment specifically has an interesting experiment that seems to imply 100k+ is feasible.