62

The commentator here offers the following criticism of green threads:

I was initially sold on the N:M model as a means of having event driven programming without the callback hell. You can write code that looks like pain old procedural code but underneath there's magic that uses userspace task switching whenever something would block. Sounds great. The problem is that we end up solving complexity with more complexity. swapcontext() and family are fairly strait-forward, the complexity comes from other unintended places.

All of a sudden you're forced to write a userspace scheduler and guess what it's really hard to write a scheduler that's going to do a better job that Linux's schedules that has man years of efforts put into it. Now you want your schedule to man N green threads to M physical threads so you have to worry about synchronization. Synchronization brings performance problems so you start now you're down a new lockless rabbit hole. Building a correct highly concurrent scheduler is no easy task.

Another critique is here:

A single process faking multiple threads has a lot of problems. One of them is that all the faked threads stall on any page fault.

My question is - are go-lang's goroutines (for a default pool) just green threads? If so - do they address the criticisms above?

1 Answer 1

87

I'm only a casual Go user, so take the following with a grain of salt.

Wikipedia defines green threads as "threads that are scheduled by a virtual machine (VM) instead of natively by the underlying operating system". Green threads emulate multithreaded environments without relying on any native OS capabilities, and they are managed in user space instead of kernel space, enabling them to work in environments that do not have native thread support.

Go (or more exactly the two existing implementations) is a language producing native code only - it does not use a VM. Furthermore, the scheduler in the current runtime implementations relies on OS level threads (even when GOMAXPROCS=1). So I think talking about green threads for the Go model is a bit abusive.

Go people have coined the goroutine term especially to avoid the confusion with other concurrency mechanisms (such as coroutines or threads or lightweight processes).

Of course, Go supports a M:N threading model, but it looks much closer to the Erlang process model, than to the Java green thread model.

Here are a few benefits of the Go model over green threads (as implemented in early JVM):

  • Multiple cores or CPUs can be effectively used, in a transparent way for the developer. With Go, the developer should take care of concurrency. The Go runtime will take care of parallelism. Java green threads implementations did not scale over multiple cores or CPUs.

  • System and C calls are non blocking for the scheduler (all system calls, not only the ones supporting multiplexed I/Os in event loops). Green threads implementations could block the whole process when a blocking system call was done.

  • Copying or segmented stacks. In Go, there is no need to provide a maximum stack size for the goroutine. The stack grows incrementally as needed. One consequence is a goroutine does not require much memory (4KB-8KB), so a huge number of them can be happily spawned. Goroutine usage can therefore be pervasive.

Now, to address the criticisms:

  • With Go, you do not have to write a userspace scheduler: it is already provided with the runtime. It is a complex piece of software, but it is the problem of Go developers, not of Go users. Its usage is transparent for Go users. Among the Go developers, Dmitri Vyukov is an expert in lockfree/waitfree programming, and he seems to be especially interested in addressing the eventual performance issues of the scheduler. The current scheduler implementation is not perfect, but it will improve.

  • Synchronization brings performance problem and complexity: this is partially true with Go as well. But note the Go model tries to promote the usage of channels and a clean decomposition of the program in concurrent goroutines to limit synchronization complexity (i.e. sharing data by communicating, instead of sharing memory to communicate). By the way, the reference Go implementation provides a number of tools to address performance and concurrency issues, like a profiler, and a race detector.

  • Regarding page fault and "multiple threads faking", please note Go can schedule goroutine over multiple system threads. When one thread is blocked for any reason (page fault, blocking system calls), it does not prevent the other threads to continue to schedule and run other goroutines. Now, it is true that a page fault will block the OS thread, with all the goroutines supposed to be scheduled on this thread. However in practice, the Go heap memory is not supposed to be swapped out. This would be the same in Java: garbage collected languages do not accomodate virtual memory very well anyway. If your program must handle page fault in a graceful way, if it probably because it has to manage some off-heap memory. In that case, wrapping the corresponding code with C accessor functions will simply solve the problem (because again C calls or blocking system calls never block the Go runtime scheduler).

So IMO, goroutines are not green threads, and the Go language and current implementation mostly addresses these criticisms.

9
  • 2
    An excellent and detailed response to the question :)
    – Tuxdude
    Commented Sep 23, 2015 at 5:58
  • 1
    I love this answer, but do you have any references to how/when the OS-threads are created?
    – Lars
    Commented Aug 22, 2016 at 10:38
  • 16
    Note that the “green thread” article on Wikipedia has been changed to state “threads that are scheduled by a runtime library or virtual machine (VM)”; which means that by that definition your answer would not be correct anymore, as the Go runtime does the scheduling/management. I think it's more helpful to define green threads as user-space threads contrasting OS-threads. And then, yes, goroutines are green threads for sure.
    – mknecht
    Commented Oct 22, 2017 at 10:04
  • 3
    2nd that @mknecht. It's not about the VM, it's about runtime. And Go definitely has a runtime. (which manages the threading model and garbage collection).
    – Tim Harper
    Commented May 10, 2018 at 15:49
  • 2
    @CAMOBAP That statement refers to the green threads library in Suns Java implementation. Suns documentation linked by user454322 states "system threads on Linux are not taken advantage of and so the Java virtual machine is not scalable when additional CPUs are added". From that document I get the impression that Java's green threads implementation ran on a single OS thread and was developed for systems that did not support native multithreading.
    – JanKanis
    Commented Aug 1, 2020 at 6:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.