Show HN: Runloom – Go-style coroutines for Python free-threaded

Hacker News Top Tools

Summary

Runloom is a new Python library that provides Go-style stackful coroutines and a work-stealing scheduler for free-threaded Python (3.13t/3.14t), allowing blocking code to run concurrently across cores without the GIL. It claims to match or beat Go in spawn throughput and scheduling performance.

No content available
Original Article
View Cached Full Text

Cached at: 07/10/26, 03:21 PM

robertsdotpm/runloom

Source: https://github.com/robertsdotpm/runloom

Runloom

Go-style stackful coroutines for Python. Write blocking code — fiber(fn), plain recv/send, no async/await — and run a million of them across every core in one process. Hand-rolled asm context switch + C work-stealing scheduler + netpoll, built for free-threaded Python 3.14t (GIL off).

import threading, runloom
from urllib.request import urlopen
runloom.monkey.patch()

def crawl(url):
    # urlopen() looks blocking -- but monkey.patch() parks the goroutine on the
    # socket instead of the OS thread, so all 64 fetches overlap on real cores.
    body = urlopen(url, timeout=10).read()
    print(threading.get_native_id(), len(body))

def main():
    for _ in range(64):
        runloom.fiber(crawl, "http://example.com")

runloom.run(8, main)   # 8 hub threads -> real cores on 3.14t (GIL off)

Runloom vs Go

Same box (64c, free-threaded CPython 3.13t), 8 hubs / GOMAXPROCS=8, warm steady-state. Go ≈ 2.1 M spawn/s here.

metricrunloomGoverdict
spawn — pure C (c_entry)2.29 M/s2.10 M/sbeats Go
spawn — Python (runloom.fiber)1.35 M/s2.10 M/s0.65×
context switch~75 ns yield · ~560 ns chan RT~50 ns Gosched~parity
conn/s — churn (new conn per req)~75–78 k/s~75–78 k/sparity
req/s — keep-alive echo, Python handler596 k/s603 k/s0.99× — parity (C handler beats Go)
memory — empty parked fiber8.8 KB2.7 KB3.3× (the one real gap)

The short story: on spawn, scheduling, and throughput, runloom trades blows with Go and beats it on raw spawn — a stackful coroutine runtime on CPython matching a compiled language even with a Python handler (596 k vs 603 k req/s at saturation; a C handler beats Go). The one honest gap left is memory: a suspended fiber carries a CPython eval frame, ~3.3× Go’s per-fiber RSS. Full cross-runtime numbers + cold spawn-vs-N curves: benchmark report · perf summary.

runloom.optimize("throughput")   # runloom.fiber -> max spawn rate (fiber_fast)
runloom.optimize("memory")       # runloom.fiber -> small right-sized stacks (default)

Install

pip install runloom
import runloom      # scheduler + channels, plus monkey/time/context/sync/aio

Prebuilt wheels (no compiler needed) for CPython 3.11–3.14 on Linux (x86_64/aarch64), macOS (arm64/x86_64), Windows (AMD64); source build elsewhere. No runtime dependencies.

What it is

  • Hand-rolled asm context switch (x86_64 SysV, aarch64) — ~80 ns/swap, no syscall; Windows Fibers / POSIX ucontext fallback.
  • M:N work-stealing scheduler (3.13t) — Chase-Lev deque per hub, per-hub MPSC submission, woken goroutines routed back to their origin hub.
  • Per-goroutine PyThreadState snapshot — cframe, datastack, exc_info, contextvars, recursion; a million yielded goroutines share their hub threads with no frame-chain cliff.
  • netpoll — epoll / kqueue / IOCP / WSAPoll / select; goroutines park transparently on fd readiness, lost-wake-free 3-state park-commit.
  • Go-style channelsChan(capacity), select, for v in ch.
  • Stall isolation + recovery — one unanticipated blocking call stalls only its hub, and the runtime detects + recovers it (default on, 3.13t).
  • monkey.patch() makes blocking stdlib (socket, time, threading, …) cooperative, so existing blocking code runs unchanged.

Already have async def code? The runloom.aio bridge runs it on the single-threaded scheduler (runloom.aio.run(main())asyncio.run) — a zero-rewrite port path, not a multi-core speedup (use the sync API with run(n>1, main) for that).

Honest limitations

  • The multi-core win needs free-threaded CPython 3.13t (3.11+ for the frame snapshot at all). On a GIL build runloom still runs — cheap spawn, the goroutine model, netpoll — but single-core like asyncio.
  • runloom doesn’t make Python faster per core. CPython’s ~80 k pure-Python ops/s/core is a constant it can’t raise; it lets one process hit that on every core at once with a blocking model. The scheduler itself is Go-class.
  • Higher memory per goroutine than Go (~3.3× for an empty fiber — the CPython eval frame; a C handler closes most of it).
  • Preemption fires only at Python bytecode boundaries — a goroutine inside a tight pure-C call (e.g. numpy) holds its hub until it returns (same as Go + cgo).
  • Linux x86_64 / 3.13t is the primary, heavily-validated target (2 M-conn runs, fuzzing, sanitizers, formal models); other backends are maintained in-step but less deeply exercised.

Platform support

OS / archswitchnetpolltested
Linux x86_64fcontext-asmepollyes — hw, 3.11 / 3.12 / 3.13t / 3.14t (primary)
Linux aarch64fcontext-asmepollqemu
macOS x86_64 / arm64fcontext-asmkqueuehw, 3.14t
FreeBSD / GhostBSDfcontext-asmkqueuehw, 3.12
Windows 10/11 / Server 2022FibersIOCP→WSAPoll→selecthw, 3.14t
Solaris / Android / other BSDucontext / asmselect / epoll / kqueuereview

Docs & layout

Full guide in docs/: Quickstart · Asyncio bridge · Sync API · Channels · M:N parallelism · Cookbook · API reference

DirContents
src/runloom_c/C extension: scheduler, channels, netpoll, asm backends, M:N hubs, stall recovery
src/runloom/Python layers: aio, sync, monkey, time, runtime
tests/ · examples/ · benchmark/ · docs/tests · runnable examples · benchmarks + perf harness · docs

Build from source (contributors): pip install -e . from a clone (needs a C compiler; scripts/install.sh / scripts\install.bat bootstrap one). To hack on runloom against free-threaded CPython, use a 3.13t interpreter.

Similar Articles

Free-threaded Python: past, present, and future

Lobsters Hottest

Thomas Wouters gives a talk at PyCon US 2026 on the past, present, and future of free-threaded Python, which removes the global interpreter lock (GIL) to allow parallel thread execution.

Go-Flavored Concurrency in C

Hacker News Top

A detailed technical post exploring how to replicate Go's concurrency model in C using POSIX threads, mutexes, condition variables, and a worker pool, as part of the Solod transpiler project.

Gossamer: a Rust-flavoured language with real goroutines and pause-free memory

Hacker News Top

Gossamer is a new programming language inspired by Rust that features real goroutines, pause-free deterministic memory management with reference counting and arenas, and a bytecode VM with LLVM compilation. It aims to provide expressive syntax without a borrow checker or garbage collector pauses.

Silk: Open-source cooperative fiber scheduler

Hacker News Top

Silk is an open-source cooperative fiber scheduler for Linux with per-CPU scheduler threads, io_uring integration, and topology-aware work-stealing, designed for high concurrency with low overhead.