In the Google I/O 2012 presentation Go Concurrency Patterns, Rob Pike mentions that several goroutines can live in one thread. Does this imply that they are implemented as coroutines? If not, how they are implemented? Links to source code would be welcome.
6 Answers
IMO, a coroutine implies supporting of explicit means for transferring control to another coroutine. That is, the programmer programs a coroutine in a way when they decide when a coroutine should suspend execution and pass its control to another coroutine (either by calling it or by returning/exiting (usually called yielding)).
Go's "goroutines" are another thing: they implicitly surrender control at certain indeterminate points1 which happen when the goroutine is about to sleep on some (external) resource like I/O completion, channel send etc. This approach combined with sharing state via channels enables the programmer to write the program logic as a set of sequential light-weight processes which removes the spaghetti code problem common to both coroutine- and event-based approaches.
Regarding the implementation, I think they're quite similar to the (unfortunately not too well-known) "State Threads" library, just quite lower-level (as Go doesn't rely on libc
or things like this and talks directly to the OS kernel) — you could read the introductory paper for the ST library where the concept is quite well explained.
Update from 2023-08-25: Russ Cox has written a good essay on why a standard coroutine package for Go would be useful, and how it could look like.
1 In fact, these points are less determinate than those of coroutines but more determinate than with true OS threads under preemptive multitasking, where each thread might be suspended by the kernel at any given point in time and in the flow of the thread's control.
Update on 2021-05-28: actually, since Go 1.14, goroutines are scheduled (almost) preemptively.
It should be noted though, that it's still not that hard-core preemption a typical kernel does to the threads it manages but it's quite closer than before; at least it's now impossible for a goroutine to become non-preemptible once it enters a busy loop.

- 51,517
- 14
- 93
- 176
-
Footnote 1 is very helpful. Thanks. – updogliu Feb 28 '19 at 05:35
-
Your interpretation of coroutins seems to coincide with mine. Your answer made me realise that **coroutins are not concurrent**. (They just do not need a global call stack to pass control around.) – Alexey Mar 14 '19 at 09:12
-
@Alexey, you might also find [this classic essay](http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/) useful—beside other things, it deals with that "stack vs heap" thing nicely. – kostix Mar 14 '19 at 11:26
-
@Alexey Co-routines **are concurrent**, but are not capable of parallelism. Unlike the general English word _concurrent_, in programming / CS concurrency means able to be executed out-of-order (opposite of sequentially), but not necessarily in parallel. – Eyal Roth Jan 25 '20 at 15:17
-
@EyalRoth, according to what i have understood from this answer, co-routines are not able to be executed out-of-order, as the control is passed explicitly. – Alexey Jan 25 '20 at 20:27
-
@Alexey You could design co-routines to yield control control to one another in a serial manner, but there are other designs. For instance, have one "central" coroutine that invokes each of the other "work" coroutines, which work for a bit and then yield back control to the "central" coroutine. It is up to the "central" coroutine to choose in which order to execute the "work" coroutines (it could even be random). – Eyal Roth Jan 26 '20 at 13:05
-
@EyalRoth, i still do not get your point: in your example with the central co-routine there is no concurrency. For example, use of Python generators is not an example of concurrency. – Alexey Jan 26 '20 at 13:52
-
@Alexey The "work" coroutines are executing in an undefined order. Sure, every coroutine always executes in a deterministic order in relation to itself, but not in relation to the other "work" coroutines. – Eyal Roth Jan 26 '20 at 14:38
-
@EyalRoth, i suppose that it depends on the definition of co-routines. In this answer it is suggested that co-routines pass control around explicitly, so there is no non-determinism: co-routines decide when and to whom they yield control. – Alexey Jan 26 '20 at 17:32
-
@Alexey Passing control explicitly does not necessarily mean deterministically. In my example, the work coroutines always (deterministically) yield control to the central coroutine, but the central may dynamically (non-deterministically) decide to yield control to whichever work coroutine at a time. – Eyal Roth Jan 26 '20 at 18:41
-
@EyalRoth, you are confusing dynamic decision with non-deterministic decision. If the central co-routine decides to yield control itself, the control is passed deterministically. – Alexey Jan 26 '20 at 22:28
-
@Alexey I'm not sure what do you refer here as "deterministic". The central coroutine can determine to pass control to which work coroutine according to a random generator, a work-balancing algorithm, IO events, or what not. That's possible as long as the work coroutine do not depend on each other for completing their own tasks. This is the essence of concurrency. – Eyal Roth Jan 27 '20 at 02:47
-
@EyalRoth, use if random number generator does not make a program concurrent. Nondeterminism is not randomness. In a concurrent program, the order of execution is partially undetermined/unspecified, and some parts can be executed in parallel. If the central co-routine yields control and then needs to get it back before it can proceed, this is not concurrency. – Alexey Jan 27 '20 at 08:02
-
1@Alexey I believe you are confusing determinism with cooperation. In preemtive multitasking (threads), the program relies on the OS to decide when to suspend concurrently running tasks; in non-preemptive (cooperative) multitasking, the program defines how to split up each of its concurrent tasks (coroutines). In both cases, concurrency is achieved; i.e, the order of completion of the tasks is dynamic and (often) unpredictable. – Eyal Roth Jan 27 '20 at 12:01
Not quite. The Go FAQ section Why goroutines instead of threads? explains:
Goroutines are part of making concurrency easy to use. The idea, which has been around for a while, is to multiplex independently executing functions—coroutines—onto a set of threads. When a coroutine blocks, such as by calling a blocking system call, the run-time automatically moves other coroutines on the same operating system thread to a different, runnable thread so they won't be blocked. The programmer sees none of this, which is the point. The result, which we call goroutines, can be very cheap: they have little overhead beyond the memory for the stack, which is just a few kilobytes.
To make the stacks small, Go's run-time uses resizable, bounded stacks. A newly minted goroutine is given a few kilobytes, which is almost always enough. When it isn't, the run-time grows (and shrinks) the memory for storing the stack automatically, allowing many goroutines to live in a modest amount of memory. The CPU overhead averages about three cheap instructions per function call. It is practical to create hundreds of thousands of goroutines in the same address space. If goroutines were just threads, system resources would run out at a much smaller number.
-
4Since v1.3 golang stack switched from segmented model to a contiguous model. See the [release note](https://golang.org/doc/go1.3#stacks) of Go 1.3. Actually, the FAQ has updated accordingly :-) – updogliu Feb 28 '19 at 07:23
Whether a goroutine is a proper coroutine or just something similar is often discussed on https://groups.google.com/forum/?fromgroups=#!forum/golang-nuts. Some people can argue about such subtleties, but for most of it: goroutine is a coroutine.
Have a look at https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw/edit to understand how the scheduler works.

- 40,468
- 7
- 81
- 87
Goroutine is a separate "thread" of execution. It is IMO not really comparable to a coroutine. In the first approximation, goroutines can be implemented by real OS threads. AFAIK, that was the case of early versions of gccgo. Another difference is that goroutines can get preempted.
Current Go compilers implement goroutines as very lightweight, user space "threads". One distinct feature wrt to eg. green threads is that goroutines can get switched to different OS threads.
I think you can find some related bits of interest here: proc.c

- 87,403
- 16
- 175
- 139
-
-
1@Sławosz: See http://en.wikipedia.org/wiki/Preemption_(computing). In short, there's cooperative scheduling (coroutines, yield, ...) and preemptive scheduling (OS threads, goroutine, ...) – zzzz Aug 05 '13 at 13:25
-
4I don't believe goroutines are preemptively scheduled. I thought goroutines just have certain points at which they check in with the scheduler for a possible context switch (e.g., at function calls, at i/o, etc). – weberc2 Jun 09 '16 at 18:44
Per Coroutines for Go by Russ Cox
In Short
- goroutine creates a new concurrent, parallel control flow
- coroutine creates a new concurrent, non-parallel control flow.
Since there are more answers about the goroutine, here are some more details of coroutines from the Coroutines for Go
- Coroutines provide concurrency without parallelism: when one coroutine is running, the one that resumed or yielded to it is not. Coroutines are a useful building block for writing programs that want concurrency for program structuring but not for parallelism
- Because coroutines run one at a time and only switch at specific points in the program, the coroutines can share data among themselves without races. The explicit switches serve as synchronization points, creating happens-before edges.
- Because scheduling is explicit (without any preemption) and done entirely without the operating system, a coroutine switch takes around ten nanoseconds, usually even less. Startup and teardown are also much cheaper than threads.
- a goroutine switch is closer to a few hundred nanoseconds because the Go runtime takes on some of the scheduling work. However, goroutines still provide the full parallelism and preemption of threads.

- 43,869
- 19
- 177
- 214
Wikipedia says, "There is no single precise definition of coroutine." Whether goroutines are coroutines depends on which definition of coroutine you choose. If you read the Wikipedia page on coroutines, most of what is described really doesn't match goroutines at all. For example, goroutines don't use yield/resume.

- 18,138
- 28
- 107
- 192