Units of execution¶
The things that run: processes, threads, and the lighter units — goroutines, virtual threads, coroutines, tasks — that runtimes schedule on top of them.
All categories · How they connect
- Process — A running program with its own address space, open files and at least one thread; two processes share nothing unless they arrange to.
- Child process — A process started by another program, which can pass it input, read its output, wait for it and learn how it ended.
- Thread — A sequence of execution inside a process, with its own stack but sharing the process's memory with every other thread in it.
- Daemon and detached threads — A thread that does not keep its program alive: when the program ends, the thread is stopped wherever it happens to be.
- Green threads and M:N scheduling — Threads implemented by a language runtime instead of the operating system, many of them multiplexed onto a smaller number of OS threads.
- Goroutine — Go's unit of concurrency: a function call started with the
gostatement and scheduled by the Go runtime onto a small pool of operating-system threads. - Virtual thread — Java's lightweight thread, final in JDK 21: a
Threadthat the JVM schedules onto a few carrier platform threads, cheap enough to start one per task.
- Goroutine — Go's unit of concurrency: a function call started with the
- UI thread — The one thread a graphical toolkit allows to touch its widgets: long work goes to other threads or tasks, and its results are posted back to that thread.
- Coroutine — A function that can suspend itself part-way through and be resumed later from the same point, keeping its local state in between.
- Fiber — A coroutine with its own stack that is switched to explicitly — the building block several green-thread runtimes are made of.
- Task (async) — A unit of async work handed to a runtime — a future being driven to completion — far cheaper than a thread because it holds no stack of its own while it waits.
- Thread pool and executor — A set of threads that run submitted tasks one after another, so the cost of starting a thread is paid once rather than once per task.
- Context switch — Saving one thread's or process's CPU state and loading another's so that it can run; switching between threads is cheaper than between processes, and between async tasks cheaper still.
- Thread-local storage — A variable with a separate copy per thread, so each thread sees only its own value and no lock is needed.
Inside this category¶
flowchart LR
n_subprocess["Child process"]
n_coroutine["Coroutine"]
n_daemon_thread["Daemon and detached threads"]
n_fiber["Fiber"]
n_goroutine["Goroutine"]
n_green_thread["Green threads and M:N scheduling"]
n_process["Process"]
n_async_task["Task (async)"]
n_thread["Thread"]
n_thread_pool["Thread pool and executor"]
n_ui_thread["UI thread"]
n_virtual_thread["Virtual thread"]
n_async_task ---|vs| n_thread
n_daemon_thread -->|is a| n_thread
n_fiber -->|is a| n_coroutine
n_goroutine -->|is a| n_green_thread
n_green_thread -->|is a| n_thread
n_process ---|vs| n_thread
n_subprocess -->|is a| n_process
n_thread_pool -->|uses| n_thread
n_ui_thread -->|is a| n_thread
n_virtual_thread -->|is a| n_green_thread