Goroutines
Async functions vs goroutines
Section titled “Async functions vs goroutines”In TypeScript you mark a function async and await its result. The function pauses at every await and yields back to the event loop, but everything still runs on one thread:
async function processUser(id: number) { const user = await fetchUser(id); return user;}await processUser(1); // you must await or .then() to consume itIn Go you prepend go to any function call. That call is dispatched as a goroutine — a lightweight, independently executing unit managed by the Go runtime. No async keyword on the function, no await at the call site:
go processUser(1) // fires immediately in the backgroundThe critical difference: a JavaScript async function is still single-threaded. A goroutine can genuinely run in parallel on a different OS thread.
Launching goroutines
Section titled “Launching goroutines”// TypeScript: async/await (single-threaded event loop)async function greet(name: string): Promise<void> { console.log(`Hello from ${name}`);}
// sequentialawait greet("Alice");await greet("Bob");
// concurrent (still one thread, interleaved via event loop)await Promise.all([greet("Alice"), greet("Bob")]);// Go: goroutines (truly concurrent)package main
import ( "fmt" "sync")
func greet(name string, wg *sync.WaitGroup) { defer wg.Done() // signal WaitGroup when done fmt.Printf("Hello from %s\n", name)}
func main() { var wg sync.WaitGroup names := []string{"Alice", "Bob", "Carol"}
for _, name := range names { wg.Add(1) // register before launching go greet(name, &wg) // launch goroutine }
wg.Wait() // block until all goroutines finish fmt.Println("All done!")}sync.WaitGroup — waiting for goroutines
Section titled “sync.WaitGroup — waiting for goroutines”sync.WaitGroup is Go’s primary tool for waiting on a group of goroutines. It works like Promise.all but uses a counter instead of an array:
wg.Add(n)— increment the counter before launching (not inside the goroutine)wg.Done()— decrement when the goroutine finishes (almost always viadefer)wg.Wait()— block until the counter reaches zero
Rule: always call
wg.Add(1)beforego f(). If you call it inside the goroutine the scheduler might reachwg.Wait()before the goroutine even starts, andWaitreturns immediately with work still pending.
Anonymous goroutines
Section titled “Anonymous goroutines”Just like immediately-invoked arrow functions in JS, you can launch an anonymous goroutine inline:
// TypeScript: immediately invoked async(async () => { const result = await doSomething(); console.log(result);})();// Go: immediately launched anonymous goroutinego func() { result := doSomething() fmt.Println(result)}() // trailing () invokes the function literal immediatelypackage main
import ( "fmt" "sync")
func printSquare(n int, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("%d² = %d\n", n, n*n)}
func main() { var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) go printSquare(i, &wg) } wg.Wait() fmt.Println("All squares printed")}Loading Go runtime (first run only, ~8 MB)…