Remix.run Logo
Rohansi 3 days ago

`await` is only logically blocking. Internally the code in an async function is split up between each `await` so that each fragment can be called separately. They are cooperatively scheduled so `await` is sugar for 1) ending a fragment, 2) registering a new fragment to run when X completes, and 3) yielding control back to the scheduler. None of this internal behavior is present for non-async functions - in C# they run directly on bare threads like C++.

Go's goroutines are comparable to async/await but everything is transparent. In that case it's managed by the runtime instead of a bit of syntactic sugar + libraries.

neonsunset 2 days ago | parent [-]

Goroutines are also more limited from UX perspective because each goroutine is a true green thread with its own virtual stack. This makes spawning goroutines much more expensive (asynchronously yielding .NET tasks start at just about 100B of allocated memory), goroutines are also very difficult to compose and they cannot yield a value requiring you to emulate task/promise-like behavior by hand by passing it over a channel or writing it to a specific location, which is more expensive.