Goroutines are a fundamental concept in Go that allow you to run functions concurrently. They are lightweight threads managed by the Go runtime, making it easy to perform multiple tasks simultaneously without the overhead of traditional threads.
Key Concepts
-
Concurrency vs. Parallelism:
- Concurrency: Structuring a program to handle multiple tasks at once.
- Parallelism: Executing multiple tasks simultaneously, typically on multiple processors.
-
Goroutines:
- Lightweight, managed by the Go runtime.
- Created using the
go
keyword. - Can run concurrently with other goroutines.
-
Channels:
- Used for communication between goroutines.
- Allow goroutines to synchronize and share data.
Creating a Goroutine
To create a goroutine, you simply prefix a function call with the go
keyword. Here’s a basic example:
package main import ( "fmt" "time" ) func sayHello() { fmt.Println("Hello, World!") } func main() { go sayHello() // This starts a new goroutine time.Sleep(1 * time.Second) // Wait for the goroutine to finish }
Explanation
go sayHello()
: This starts a new goroutine that runs thesayHello
function.time.Sleep(1 * time.Second)
: This ensures the main function waits long enough for the goroutine to complete. Without this, the program might exit before the goroutine has a chance to run.
Practical Example: Concurrent Tasks
Let's create a more practical example where we perform two tasks concurrently.
package main import ( "fmt" "time" ) func task1() { for i := 1; i <= 5; i++ { fmt.Printf("Task 1 - Count: %d\n", i) time.Sleep(500 * time.Millisecond) } } func task2() { for i := 1; i <= 5; i++ { fmt.Printf("Task 2 - Count: %d\n", i) time.Sleep(700 * time.Millisecond) } } func main() { go task1() go task2() time.Sleep(4 * time.Second) // Wait for both goroutines to finish }
Explanation
task1
andtask2
are two functions that print a count with different delays.- Both functions are started as goroutines using the
go
keyword. time.Sleep(4 * time.Second)
ensures the main function waits long enough for both goroutines to complete.
Common Mistakes
-
Forgetting to Wait: If the main function exits before the goroutines complete, the program will terminate prematurely.
- Solution: Use
time.Sleep
or synchronization mechanisms like channels orsync.WaitGroup
.
- Solution: Use
-
Race Conditions: When multiple goroutines access shared resources without proper synchronization.
- Solution: Use channels or other synchronization primitives to manage access to shared resources.
Exercise
Task
Create a program that starts three goroutines. Each goroutine should print a message and its ID (1, 2, or 3) five times, with a delay of 300 milliseconds between each print. Ensure the main function waits for all goroutines to complete.
Solution
package main import ( "fmt" "sync" "time" ) func printMessage(id int, wg *sync.WaitGroup) { defer wg.Done() for i := 1; i <= 5; i++ { fmt.Printf("Goroutine %d - Message %d\n", id, i) time.Sleep(300 * time.Millisecond) } } func main() { var wg sync.WaitGroup for i := 1; i <= 3; i++ { wg.Add(1) go printMessage(i, &wg) } wg.Wait() // Wait for all goroutines to finish }
Explanation
sync.WaitGroup
is used to wait for all goroutines to complete.wg.Add(1)
increments the WaitGroup counter for each goroutine.defer wg.Done()
decrements the counter when the goroutine completes.wg.Wait()
blocks the main function until the counter is zero, ensuring all goroutines have finished.
Conclusion
Goroutines are a powerful feature in Go that enable concurrent programming with minimal overhead. By understanding how to create and manage goroutines, you can build efficient and responsive applications. In the next section, we will explore channels, which are essential for communication and synchronization between goroutines.
Go Programming Course
Module 1: Introduction to Go
Module 2: Basic Concepts
Module 3: Advanced Data Structures
Module 4: Error Handling
Module 5: Concurrency
Module 6: Advanced Topics
Module 7: Web Development with Go
Module 8: Working with Databases
Module 9: Deployment and Maintenance
- Building and Deploying Go Applications
- Logging
- Monitoring and Performance Tuning
- Security Best Practices