A playful simulation of Go's internal runtime scheduler, written in pure Go β featuring:
- M:P:G model (OS threads, processors, goroutines)
- Network polling simulation
- Work stealing between processors
- Preemption for long-running goroutines
- Blocking syscalls and resuming
Inspired by the real Go scheduler, built to learn and explore how concurrency works under the hood.
- Simulates:
M
(OS kernel threads)P
(logical processors with run queues)G
(goroutines / lightweight tasks)
- Network poller that injects tasks at random
- Handling blocking syscalls (with goroutines moving to a blocked queue)
- Simple round-robin binding of threads to processors
- Work stealing across processors to balance load
- Preemption: if a goroutine runs too long, itβs put back into the queue
type Scheduler struct { ... }
type OSThread struct { ... }
type Processor struct { ... }
type Goroutine struct { ... }
func (s *Scheduler) Start()
func (s *Scheduler) Go(task Task)
func (s *Scheduler) RunMachine(...)
...
All the logic lives in the internal
package, written in idiomatic Go.
Clone and run as a simple experiment or base for deeper exploration.
git clone https://github.com/omniflare/go-routine-scheduler
cd go-routine-scheduler
go run cmd/main.go
Inside main.go
you can find:
scheduler := internals.NewSchedler(2, 3)
scheduler.Start()
for i :=range 10 {
scheduler.GO(func() {
fmt.Printf("GOROUTINE %d running...\n", i)
time.Sleep(50 * time.Millisecond)
})
}
time.Sleep(5 * time.Second)
This project is a learning experiment to understand how the Go scheduler manages thousands of goroutines efficiently β and to see how concepts like preemption, work stealing, and network polling look in code.
https://github.com/golang/go/blob/master/src/runtime/proc.go
Feel free to fork, explore, add features (e.g., priority scheduling, dynamic P/M management) and open PRs!