Sławosz
Sławosz

Reputation: 11687

Is a Go goroutine a coroutine?

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.

Upvotes: 91

Views: 53094

Answers (7)

zangw
zangw

Reputation: 48406

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.

Why Coroutines in Go?

The coroutines proposal in Go aims to enhance the way concurrency is handled. Unlike Goroutines, which emphasize parallelism, coroutines in Go are designed to facilitate concurrency without necessarily invoking parallelism. This approach is particularly beneficial in scenarios requiring structured program design with concurrent elements while avoiding the complexities and potential pitfalls of parallel execution.

Goroutine vs Coroutine

  • Coroutines focus on yielding and resuming execution at specific points, enabling concurrency but not parallelism. for certain programming scenarios where controlled execution flow is more important than simultaneous task processing.
  • Goroutines in Go offer full parallelism and preemption, with the runtime handling some scheduling work. They can run multiple control flows concurrently and in parallel.

Upvotes: 5

Gedw99
Gedw99

Reputation: 871

An accelerated coroutine, as opposed to go routines is here.

https://stealthrocket.tech/blog/fairy-tales-of-workflow-orchestration

https://github.com/stealthrocket/coroutine

It has the advantage of giving you an async programming style as well as state being able to be rehydrated.

Upvotes: 0

kostix
kostix

Reputation: 55473

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.

Upvotes: 86

clay
clay

Reputation: 20400

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.

Upvotes: 0

K Z
K Z

Reputation: 30453

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.

Upvotes: 68

Volker
Volker

Reputation: 42413

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.

Upvotes: 5

zzzz
zzzz

Reputation: 91253

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

Upvotes: 2

Related Questions