Concurrency
Goroutines
// Goroutines
// A goroutine is a lightweight thread managed by the Go runtime.
// Example: go f(x, y, z) starts a new goroutine running f(x, y, z).
package main
import (
"fmt"
"time"
)
// Function to be executed in a goroutine
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world") // Start a goroutine
say("hello") // Execution in the main goroutine
}
Channels
package main
import (
"fmt"
"time"
)
func main() {
// Loop that runs 5 Sleepy gophers go routines
c := make(chan int)
for i := 0; i < 5; i++ {
go sleepyGopher(i, c)
}
// Loop Receives Gopher id
for i := 0; i < 5; i++ {
gopherId := <-c
fmt.Println("gopher ", gopherId, " has Finished Sleeping")
}
}
// sleepy Gopher Sends id when finish sleeping
func sleepyGopher(id int, c chan int) {
time.Sleep(5 * time.Second)
fmt.Println("......", id, " snore.....")
c <- id
}
Select
package main
import (
"fmt"
"time"
)
func main() {
// Loop that runs 5 Sleepy gophers go routines
c := make(chan int)
for i := 0; i < 5; i++ {
go sleepyGopher(i, c)
}
timeOut := time.After(3 * time.Second)
for i := 0; i < 5; i++ {
// select acts lke switches it keeps waiting for the two cases
select {
case id := <-c:
fmt.Print("gopher ", id, " has finished")
case <-timeOut:
fmt.Println("my patience ran out")
return
}
}
}
// sleepy goher sleeps for 5 seconds
func sleepyGopher(id int, c chan int) {
time.Sleep(5 * time.Second)
fmt.Println("......", id, " snore.....")
c <- id
}
Range and Close
package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x // Send the current fibonacci number to the channel
x, y = y, x+y
}
close(c) // Sender closes the channel to signal the end of sequence
}
func main() {
// Create a channel with a buffer capacity of 10 (optional)
c := make(chan int, 10)
// Launch the fibonacci function as a goroutineblob:file:///a9674d55-dac3-43f9-9743-4a7c48bb3063
go fibonacci(cap(c), c) // Pass the channel capacity to fibonacci
// Use a range loop to receive and print fibonacci numbers
for i := range c {
fmt.Println(i)
}
}
mutex
To prevent data races, we'll use a mutex to synchronize access to this shared resource.
package main
import (
"fmt"
"sync"
)
var (
sharedResource int // Shared resource accessed by workers
mutex sync.Mutex // Mutex to synchronize access to sharedResource
)
// worker is a function that performs some work.
// It takes a waitgroup as a parameter to signal when it's done.
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // Signal that this worker is done when the function exits
for i := 0; i < 10; i++ {
fmt.Printf("Worker %d starting\n", id)
// Lock the mutex before accessing the shared resource
mutex.Lock()
sharedResource++
// Perform the work here, using the shared resource
// This is just a placeholder, you can replace it with the actual work
fmt.Printf("Worker %d incremented shared resource to: %d\n", id, sharedResource)
mutex.Unlock() // Unlock the mutex after accessing the shared resource
fmt.Printf("Worker %d done\n", id)
}
}
func main() {
var wg sync.WaitGroup // Create a new waitgroup
wg.Add(1) // Add 1 to the waitgroup to indicate that we're waiting for 1 worker
go worker(1, &wg) // Start the worker goroutine
wg.Wait() // Wait until all workers are done
}
What are two potential problems with locking a mutex?
It might block other goroutines that are also trying to lock the mutex; it could lead to deadlock.
Event loops and go-routines
Wait Groups
package main
import (
"fmt"
"sync"
)
// worker is a function that performs some work.
// It takes a waitgroup as a parameter to signal when it's done.
func worker(wg *sync.WaitGroup) {
defer wg.Done() // Signal that this worker is done when the function exits
for i := 0; i < 10; i++ {
fmt.Printf("Worker %d starting\n", i)
// Perform the work here
fmt.Printf("Worker %d done\n", i)
}
}
func main() {
var wg sync.WaitGroup // Create a new waitgroup
wg.Add(1) // Add 1 to the waitgroup to indicate that we're waiting for 1 worker
go worker(&wg) // Start the worker goroutine
wg.Wait() // Wait until all workers are done
}
Last updated