Golang goroutines: go routine examples, the go keyword, and waiting for work

Golang goroutine and golang goroutines: goroutine in golang with the go keyword, go goroutines and go routine spelling, minimal goroutine example, waiting with channels or sync.WaitGroup, and links to threads vs goroutines and channels.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Golang goroutines: go routine examples, the go keyword, and waiting for work

Searches for golang goroutine, golang goroutines, goroutine, goroutines, go goroutines, goroutine in golang, go routine, go routine example, golang goroutine example, and goroutine example all point at the same mechanism: the go statement starts a new goroutine, a concurrent call that shares your program's memory. Every Go program already has a main goroutine; you add more when you want overlapping work. For how that differs from OS threads, see goroutine vs thread in Go. To review declaration syntax before you attach go to a call, see functions vs methods in Go.

Examples assume a recent Go toolchain on Linux. Snippets that use only the standard library are written so you can paste them into a single main.go and run go run ..


Golang goroutine in one sentence

A goroutine is a lightweight concurrent function invocation. You write go f() or go func() { ... }(); the runtime runs it alongside the rest of your program instead of blocking the caller at the call site.


First golang goroutine example (and the empty output gotcha)

The smallest goroutine example starts work in the background:

go
package main

import "fmt"

func main() {
	go fmt.Println("Hello World")
}

If you run that, you will often see no output: when main returns, the whole process exits and unfinished goroutines are cut off. That surprises people searching for golang goroutine example or goroutine example—so the first lesson is synchronization, not more go lines.

A tiny sleep is not reliable on fast machines; a channel (or sync.WaitGroup) makes the behavior deterministic. Here main waits until the goroutine signals completion:

go
package main

import "fmt"

func main() {
	done := make(chan struct{})
	go func() {
		fmt.Println("Hello from goroutine")
		close(done)
	}()
	<-done
}
Output

Running that locally prints one line such as Hello from goroutine. The same pattern scales to passing data on the channel instead of an empty struct when you need results.


Starting go goroutines on functions and literals

Any call can be prefixed with go as long as the callee's signature is valid. Named function:

go
go saveToDisk(path)

Anonymous goroutine (very common):

go
go func(user string) {
	// work for user
}("alice")

Note the trailing () on the literal: go func() { ... }() starts the goroutine immediately.


Waiting for golang goroutines

time.Sleep (teaching only)

You may see tutorials use time.Sleep so main stays alive. It is brittle: the right duration depends on load and hardware. Prefer explicit waits below for real code.

sync.WaitGroup (fan-out / fan-in)

WaitGroup counts outstanding goroutines; each worker calls Done() (usually deferred), and main calls Wait(). This is a standard golang goroutine pattern when you know how many tasks you launched:

go
package main

import (
	"fmt"
	"sync"
	"time"
)

func work(id int, wg *sync.WaitGroup) {
	defer wg.Done()
	time.Sleep(50 * time.Millisecond)
	fmt.Println("done", id)
}

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go work(i, &wg)
	}
	wg.Wait()
	fmt.Println("all finished")
}

Sample output (order may vary):

text
done 0
done 1
done 2
all finished

Multiple go goroutines (interleaving)

Two goroutines can make progress between each other while the scheduler multiplexes them. With a WaitGroup instead of a fixed sleep, you do not hard-code how long three iterations need:

go
package main

import (
	"fmt"
	"sync"
	"time"
)

func greetings(name string, wg *sync.WaitGroup) {
	defer wg.Done()
	for i := 0; i < 3; i++ {
		fmt.Println(i, "==>", name)
		time.Sleep(time.Millisecond)
	}
}

func main() {
	var wg sync.WaitGroup
	wg.Add(2)
	go greetings("John", &wg)
	go greetings("Mary", &wg)
	wg.Wait()
}

One local run printed lines like 0 ==> Mary and 0 ==> John before continuing; exact interleaving is nondeterministic.


What to learn next

  • Coordinate work with channels instead of ad hoc sleeps when goroutines pass data or signals.
  • HTTP servers often call go handler() patterns indirectly through net/http; see HTTP in Go for server-side context.
  • Avoid starting goroutines that you cannot shut down: pair long-lived work with context.Context cancellation in larger programs.

Summary

Golang goroutine usage boils down to the go keyword plus a plan for when work finishes. Golang goroutines and go goroutines are the same feature people sometimes type as go routine. A minimal goroutine example is not complete until you handle process exit—use channels or sync.WaitGroup so your golang goroutine example behaves the same on a laptop and in CI. Goroutine in golang is just idiomatic Go concurrency; build on channels and context as patterns grow.


References


Frequently Asked Questions

1. What is a goroutine in golang?

A goroutine is a function executing concurrently with other code in the same address space, started with the go keyword; the runtime schedules many goroutines on a smaller set of OS threads.

2. Why does my golang goroutine example print nothing?

If main returns before the goroutine runs, the process exits; use a channel receive, sync.WaitGroup, or another synchronization primitive instead of hoping a short sleep is enough.

3. Is it go routine or goroutine?

The language keyword is go; the feature is spelled goroutine as one word. People still search go routine; it means the same idea.

4. How do I wait for golang goroutines to finish?

Use sync.WaitGroup around fixed fan-out work, or pass a done channel; prefer those over long time.Sleep in real programs.
Antony Shikubu

Systems Integration Engineer

Highly skilled software developer with expertise in Python, Golang, and AWS cloud services.