Concurrent Operations

Tutorial 3 of 4

1. Introduction

1.1 Goal of the Tutorial

In this tutorial, we aim to provide a comprehensive understanding of concurrent operations in Go. We will guide you through the process of performing and managing these operations effectively, helping you harness the power of concurrency in your Go programs.

1.2 Learning Outcomes

After completing this tutorial, you will be able to:
- Understand the basics of concurrent programming
- Define and manage Goroutines
- Use channels for communication between Goroutines
- Implement select for handling multiple channels

1.3 Prerequisites

You should have a basic understanding of the Go programming language. If you're new to Go, you might want to get a grasp of the basics before proceeding with this tutorial.

2. Step-by-Step Guide

2.1 Understanding Concurrency

Concurrency in programming refers to the execution of tasks independently and potentially out-of-order while maintaining the final consistency of operations.

In Go, Concurrency is achieved using Goroutines and Channels. A Goroutine is a function that is capable of running concurrently with other functions. Channels are the pipes that connect concurrent goroutines. You can send values into channels from one goroutine and receive those values into another goroutine.

2.2 Goroutines

To define a goroutine, use the go keyword followed by a function invocation:

go functionName()  // starts a new goroutine

2.3 Channels

Channels are a typed conduit through which you can send and receive values with the channel operator, <-.

Here's how you can define a channel:

ch := make(chan int) // Creates a new channel with type int

3. Code Examples

3.1 Example 1: Simple Goroutine and Channel

package main

import (
    "fmt"
    "time"
)

func printNumbers(ch chan int) {
    for i := 1; i <= 5; i++ {
        time.Sleep(1 * time.Second)
        ch <- i // Send 'i' to channel 'ch'
    }
    close(ch)
}

func main() {
    ch := make(chan int)
    go printNumbers(ch) // Start goroutine
    for num := range ch {
        fmt.Println("Number:", num)
    }
}

In this example, we create a goroutine printNumbers. This goroutine sends numbers 1 to 5 to a channel ch after waiting for a second each time. In the main function, we continually read from the channel ch and print the number.

3.2 Example 2: Select with Channels

package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

In this code, fibonacci function generates numbers in the Fibonacci sequence and sends them on the channel c. The main function creates two channels, c and quit, and launches a goroutine that generates the Fibonacci sequence. When the sequence reaches 10 numbers, it sends a value to quit which causes the fibonacci function to return.

4. Summary

In this tutorial, we've covered the basics of concurrent programming in Go, including goroutines, channels, and select. You've learned how to define and manage goroutines, how to use channels for communication between goroutines, and how to implement select for handling multiple channels.

For further learning, you might want to explore more about buffered channels, worker pools, and select with default case in Go.

5. Practice Exercises

  1. Write a program that launches 10 goroutines to calculate the factorial of numbers 0 through 9 concurrently. Use channels to communicate the results.

  2. Modify the previous program to use a worker pool of 3 goroutines to calculate the factorials.

  3. Write a program that sends a sequence of numbers to a goroutine through a channel and have the goroutine compute the sum of the numbers and send it back through another channel.

Remember to practice regularly and explore more complex scenarios to get a deeper understanding of concurrent operations in Go. Good luck!