What are goroutines? And how do they actually work?

João Henrique Machado Silva
The Polyglot Programmer
6 min readMar 14, 2019


One of the main reasons that the Go Language has gained incredible popularity in the past few years is the simplicity it deals with concurrency with its lightweight goroutines and channels.

Concurrency is not something necessarily new, it has existed since long ago in the form of threads which are widely used in almost all applications now a days.

But first, before actually understanding what are goroutines, and no, they are not lightweight threads (although goroutines rely upon thread to run), we are going to dig into how actual threads work in the OS.

What are Threads?

A thread is the smallest unit of processing that can be performed in an OS. In most modern operating systems, a thread exists within a process — that is, a single process may contain multiple threads.

A good example is a web server.

A webserver normally is designed to handle multiple requests at once. And these requests normally are independent from each other.

So a thread can be created, or taken from a thread pool, and requests can be delegated, to achieve concurrency. But remember from the famous Rob Pike talk, "Concurrency is not Parallelism".

But is a thread lighter then a process? Let's see.

Depends on how you look at it.

In theory, a thread shares memory with another thread, and don't actually have to create a new virtual memory space when they are created, not requiring a MMU (memory management unit) context switch. And plus, the communication is simpler then processes, mainly because they can have shared memory while processes require various modes of IPC (Inter-Process Communications) like semaphores, message queues, pipes and etc.

So does that always make threads more performant then processes? Not in this multi-processor world we live in.

e.g. Linux doesn’t differentiate between threads and processes and both are called tasks. Each task can have a minimum to maximum level of sharing when cloned.

When you call fork(), a new task is created with no shared file descriptors, PIDs and memory space. When you call…