DEV Community

Cover image for All concurrency systems are created for one purpose
lbvf50mobile
lbvf50mobile

Posted on

All concurrency systems are created for one purpose

Let me put it this way. All concurrency systems are created for one purpose: not to let the CPU idle while waiting for a response. Two approaches: Event Loop and G/P/M.

Dart Event Loop

Events are added to a queue and processed from the queue in order of addition by registered callbacks. Await is syntactic sugar over a callback that sounds like this: "when the function return event happens, then we'll continue from this point." But in reality, async tells the compiler to split the function into pieces. (Interesting - how do finite state machines get built in loops?) This is cooperative multitasking. It's primitive. However you write the handler is how it will work.

G/P/M in Go

Here multitasking is preemptive. There's an abstraction of a goroutine - it's like a primitive pseudo-UNIX process where all I/O is blocking. And the complex multi-component scheduler stops and starts goroutines, moving them between cores. Essentially removing some complexity from the developer. You just write code. And the scheduler takes care that goroutines don't "starve." In short.

Dart Event Loop: event, callback, event, callback, event, callback.

G/P/M in Go: IO-block-defer-select-new-for-execution, IO-block-defer-select-new-for-execution.

If you imagine 1ms as a "day," then creating a goroutine takes only "a few minutes" - 300ns. That's why Go provides enormous capabilities for handling waves of requests, churning out cheap goroutines with their own stack. Go is ideal for high-load servers.

Meanwhile, Event Loop in Dart is perfectly suited for GUI. Every 16ms or 16 "days" there's a smart redraw of Widgets based on State. And the programmer has a model where it's clear you need to write small handlers that will be pulled from the queue, and within these 16 days they'll manage to free up space for GUI redraw. Simple and reliable. Very understandable. The mechanism is primitive.

Moreover, launching an isolate for heavy computations takes about 500μs - i.e., "half a day" - allows you to offload complex calculations to a separate OS thread, on a separate core. And then process the result with a lightweight handler to make it in time for redraw within 16 days.

TIME CREATION ANALOGY
(1 ms = 1000 μs = 1 "day")
1 ms = 1000 μs
1 μs = 1000 ns
Goroutine ≈ 300 ns ≈ 30 "seconds" ≈ "half a minute"
OS Thread 20–100 μs ≈ 50 "minutes" ≈ "one hour"
fork() 30–150 μs ≈ 1–3 "hours" ≈ "few hours"
Dart Isolate 600–1000 μs ≈ 1 "day" ≈ "one day"
fork()+exec() 300–2000 μs ≈ 1–2 "days" ≈ "couple of days"
Flutter frame 16 ms ≈ 2 "weeks" ≈ "two weeks"

ChatGPT infographics based on the text

Top comments (0)