Concurrent execution model in Go - Time & Space Complexity
When programs run tasks at the same time, it changes how long things take. We want to see how running tasks together affects the total work done.
How does doing many tasks at once change the time needed as we add more tasks?
Analyze the time complexity of the following code snippet.
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(1 * time.Second) // simulate work
fmt.Println("Worker", id, "done")
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
}
This code runs 5 workers at the same time, each doing a 1-second task concurrently.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Starting 5 concurrent worker tasks.
- How many times: 5 times, once per worker.
Each worker runs independently, so total time depends on the longest single task, not the sum.
| Input Size (n) | Approx. Operations (seconds) |
|---|---|
| 5 | 1 (all run together) |
| 10 | 1 (still all run together) |
| 100 | 1 (assuming enough resources to run all) |
Pattern observation: Total time stays about the same as tasks increase, if they run truly in parallel.
Time Complexity: O(1)
This means the total time does not grow with more tasks because they run at the same time.
[X] Wrong: "Adding more concurrent tasks always makes the program slower because it does more work."
[OK] Correct: When tasks run at the same time, total time depends on the longest task, not the number of tasks.
Understanding how concurrency affects time helps you explain real programs that do many things at once. It shows you can think about how work spreads out over time.
"What if each worker took different amounts of time? How would that affect the total time complexity?"
Practice
Solution
Step 1: Understand goroutine concept
A goroutine is a function or method that runs concurrently with other goroutines.Step 2: Identify goroutine characteristics
It is lightweight and managed by Go's runtime, unlike OS threads which are heavier.Final Answer:
A lightweight thread managed by the Go runtime -> Option AQuick Check:
Goroutine = lightweight thread [OK]
- Confusing goroutine with OS thread
- Thinking goroutine is a variable type
- Assuming goroutine runs only once
doWork()?Solution
Step 1: Recall goroutine syntax
In Go, to start a goroutine, prefix the function call with the keywordgo.Step 2: Match syntax with options
Onlygo doWork()uses the correct keyword and syntax.Final Answer:
go doWork() -> Option AQuick Check:
Start goroutine with 'go' keyword [OK]
- Using 'goroutine' keyword instead of 'go'
- Using 'start' or 'run' which are invalid
- Omitting the 'go' keyword
package main
import (
"fmt"
"time"
)
func main() {
go fmt.Println("Hello from goroutine")
fmt.Println("Hello from main")
time.Sleep(100 * time.Millisecond)
}Solution
Step 1: Understand goroutine and main execution
The goroutine prints "Hello from goroutine" concurrently, while main prints "Hello from main" immediately.Step 2: Analyze timing with Sleep
Thetime.Sleepallows the goroutine time to run before the program exits, so both lines print.Final Answer:
Hello from main\nHello from goroutine -> Option DQuick Check:
Sleep allows goroutine output after main [OK]
- Ignoring need for sleep to let goroutine run
- Assuming goroutine output always prints first
- Expecting no output due to race condition
package main
import "fmt"
func main() {
go func() {
fmt.Println("Running")
}()
}Solution
Step 1: Check syntax correctness
The anonymous function syntax and goroutine start are correct; no syntax errors.Step 2: Analyze program flow
The main function exits immediately after starting the goroutine, so "Running" may never print.Final Answer:
Program exits before goroutine runs -> Option BQuick Check:
Program ends before goroutine runs [OK]
- Thinking syntax is wrong for anonymous goroutine
- Forgetting program ends immediately
- Assuming goroutine blocks main automatically
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
fmt.Println(n)
}(i)
}
// What should be here?
}Solution
Step 1: Understand WaitGroup usage
WaitGroup tracks goroutines;wg.Add(1)before start,wg.Done()after done.Step 2: Ensure main waits for all goroutines
Callingwg.Wait()blocks main until all goroutines callDone().Final Answer:
wg.Wait() -> Option CQuick Check:
WaitGroup.Wait() waits for goroutines [OK]
- Using Sleep instead of WaitGroup for sync
- Trying to close WaitGroup (not allowed)
- Calling Done() in main instead of goroutine
Ready to prove it?
Pass the test and this pattern moves unknown
