Bird
Raised Fist0
Goprogramming~20 mins

Common concurrency patterns in Go - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Concurrency Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
Output of a simple goroutine with channel communication

What is the output of this Go program?

Go
package main

import (
	"fmt"
)

func main() {
	ch := make(chan string)
	go func() {
		ch <- "hello"
	}()
	msg := <-ch
	fmt.Println(msg)
}
Ahello
BCompilation error
CDeadlock error
DEmpty output
Attempts:
2 left
💡 Hint

Think about how channels synchronize goroutines.

❓ Predict Output
intermediate
2:00remaining
Output of select with multiple channel cases

What will this Go program print?

Go
package main

import (
	"fmt"
	"time"
)

func main() {
	ch1 := make(chan string)
	ch2 := make(chan string)

	go func() {
		time.Sleep(100 * time.Millisecond)
		ch1 <- "one"
	}()

	go func() {
		ch2 <- "two"
	}()

	select {
	case msg1 := <-ch1:
		fmt.Println(msg1)
	case msg2 := <-ch2:
		fmt.Println(msg2)
	}
}
Atwo
BDeadlock error
CCompilation error
Done
Attempts:
2 left
💡 Hint

Which channel sends first without delay?

❓ Predict Output
advanced
2:00remaining
Output of a fan-in pattern using channels

What is the output of this Go program?

Go
package main

import (
	"fmt"
)

func worker(id int, ch chan<- string) {
	ch <- fmt.Sprintf("worker %d done", id)
}

func main() {
	ch := make(chan string)
	for i := 1; i <= 3; i++ {
		go worker(i, ch)
	}
	for i := 1; i <= 3; i++ {
		msg := <-ch
		fmt.Println(msg)
	}
}
A
worker 3 done
worker 2 done
worker 1 done
BDeadlock error
CCompilation error
D
worker 1 done
worker 2 done
worker 3 done
Attempts:
2 left
💡 Hint

Order of output may vary but all workers send a message.

❓ Predict Output
advanced
2:00remaining
Output of a pipeline pattern with channel chaining

What does this Go program print?

Go
package main

import (
	"fmt"
)

func gen(nums ...int) <-chan int {
	out := make(chan int)
	go func() {
		for _, n := range nums {
			out <- n
		}
		close(out)
	}()
	return out
}

func sq(in <-chan int) <-chan int {
	out := make(chan int)
	go func() {
		for n := range in {
			out <- n * n
		}
		close(out)
	}()
	return out
}

func main() {
	c := gen(2, 3, 4)
	out := sq(c)
	for n := range out {
		fmt.Println(n)
	}
}
ADeadlock error
B
4
9
16
C
2
3
4
DCompilation error
Attempts:
2 left
💡 Hint

Think about how data flows through the pipeline.

❓ Predict Output
expert
2:00remaining
Output of a race condition with shared variable

What is the output of this Go program?

Go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var counter int
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		for i := 0; i < 1000; i++ {
			counter++
		}
		wg.Done()
	}()
	go func() {
		for i := 0; i < 1000; i++ {
			counter++
		}
		wg.Done()
	}()
	wg.Wait()
	fmt.Println(counter)
}
A2000
BCompilation error
CA number less than 2000
DDeadlock error
Attempts:
2 left
💡 Hint

Think about concurrent access to the variable without synchronization.

Practice

(1/5)
1. What is the primary purpose of a WaitGroup in Go concurrency?
easy
A. To limit the number of goroutines running at the same time
B. To send data safely between goroutines
C. To wait for a collection of goroutines to finish before continuing
D. To create new goroutines

Solution

  1. Step 1: Understand WaitGroup's role

    A WaitGroup is used to wait for multiple goroutines to complete their work.
  2. Step 2: Compare with other concurrency tools

    Channels send data, semaphores limit concurrency, and goroutines run functions concurrently.
  3. Final Answer:

    To wait for a collection of goroutines to finish before continuing -> Option C
  4. Quick Check:

    WaitGroup = wait for goroutines [OK]
Hint: WaitGroup waits for goroutines to finish, not for data passing [OK]
Common Mistakes:
  • Confusing WaitGroup with channels
  • Thinking WaitGroup limits goroutines
  • Using WaitGroup to send data
2. Which of the following is the correct syntax to start a new goroutine calling function doWork()?
easy
A. run doWork()
B. goroutine doWork()
C. start doWork()
D. go doWork()

Solution

  1. Step 1: Recall goroutine syntax

    In Go, the keyword go before a function call starts it as a goroutine.
  2. Step 2: Check options

    Only go doWork() matches the correct syntax; others are invalid keywords.
  3. Final Answer:

    go doWork() -> Option D
  4. Quick Check:

    Start goroutine with 'go' keyword [OK]
Hint: Start goroutine with 'go' keyword before function call [OK]
Common Mistakes:
  • Using non-existent keywords like 'goroutine' or 'start'
  • Omitting 'go' keyword
  • Trying to run goroutine without parentheses
3. What will be the output of this Go program?
package main
import (
  "fmt"
  "sync"
)
func main() {
  var wg sync.WaitGroup
  wg.Add(2)
  go func() {
    fmt.Println("Hello from goroutine 1")
    wg.Done()
  }()
  go func() {
    fmt.Println("Hello from goroutine 2")
    wg.Done()
  }()
  wg.Wait()
  fmt.Println("All goroutines finished")
}
medium
A. Hello from goroutine 2 Hello from goroutine 1
B. Hello from goroutine 1 Hello from goroutine 2 All goroutines finished
C. Hello from goroutine 1 All goroutines finished Hello from goroutine 2
D. All goroutines finished Hello from goroutine 1 Hello from goroutine 2

Solution

  1. Step 1: Understand WaitGroup usage

    The program adds 2 to the WaitGroup, then starts 2 goroutines that each print a message and call wg.Done().
  2. Step 2: Analyze output order

    The main goroutine waits for both goroutines to finish before printing "All goroutines finished". The two goroutine prints can appear in any order but both appear before the final print.
  3. Final Answer:

    Hello from goroutine 1 Hello from goroutine 2 All goroutines finished -> Option B
  4. Quick Check:

    WaitGroup ensures final print after goroutines [OK]
Hint: WaitGroup.Wait blocks until all Done calls complete [OK]
Common Mistakes:
  • Assuming main prints before goroutines
  • Ignoring WaitGroup synchronization
  • Expecting goroutine prints after final print
4. Identify the error in this Go code snippet using channels:
package main
import "fmt"
func main() {
  ch := make(chan int)
  go func() {
    ch <- 10
  }()
  fmt.Println(<-ch)
  fmt.Println(<-ch)
}
medium
A. Second read from channel blocks forever
B. Channel is not closed before reading
C. Channel should be buffered to send data
D. Goroutine is not started correctly

Solution

  1. Step 1: Analyze channel sends and receives

    The goroutine sends one value (10) into the channel. The main goroutine reads twice from the channel.
  2. Step 2: Identify blocking behavior

    The first read gets 10 successfully. The second read waits for another value that never comes, causing a deadlock (blocks forever).
  3. Final Answer:

    Second read from channel blocks forever -> Option A
  4. Quick Check:

    One send, two receives causes blocking [OK]
Hint: Reads must match sends; extra read blocks forever [OK]
Common Mistakes:
  • Thinking channel must be closed before reading
  • Assuming buffered channel fixes blocking here
  • Believing goroutine not started properly
5. You want to create a worker pool in Go to process 5 jobs concurrently but limit to 2 workers at a time. Which pattern correctly implements this?
hard
A. Use a buffered channel of size 2 as a semaphore to limit goroutines, and a WaitGroup to wait for all jobs
B. Start 5 goroutines without limit and use a WaitGroup to wait
C. Use an unbuffered channel to send jobs and no WaitGroup
D. Use a mutex to lock and unlock workers

Solution

  1. Step 1: Understand worker pool concurrency limit

    To limit concurrent workers, a buffered channel (semaphore) of size 2 can control how many goroutines run simultaneously.
  2. Step 2: Use WaitGroup to wait for all jobs

    A WaitGroup tracks all 5 jobs to ensure main waits until all finish before exiting.
  3. Final Answer:

    Use a buffered channel of size 2 as a semaphore to limit goroutines, and a WaitGroup to wait for all jobs -> Option A
  4. Quick Check:

    Semaphore + WaitGroup = controlled concurrency [OK]
Hint: Semaphore channel limits workers; WaitGroup waits for all [OK]
Common Mistakes:
  • Starting all goroutines without limit
  • Not using WaitGroup to wait for completion
  • Using mutex incorrectly for concurrency limit
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard