Skip to content

Golang parity problem

Posted on:18 ottobre 2024 at 14:00

This Go program processes a list of integers, classifies them as odd or even, and stores them in separate slices (odds and evens).

It achieves this using goroutines for concurrent execution, channels for communication between goroutines, and a WaitGroup for synchronization.

The full code is available on my GitHub repository

Table of contents

Open Table of contents

Step-by-Step Breakdown

1. Type Definition

type in struct {
    value    int32
    oddChan  chan int32
    evenChan chan int32
}

This struct in is designed to hold:

The struct allows each number to be paired with the necessary channels to send it to the correct destination (odd or even).

2. Global Channel Declaration

var serverChan chan in

serverChan is a global channel of type in. It is used to send data to a central server (goroutine) for processing.

3. Server Function (Goroutine)

func Server() {
    for v := range serverChan {
        if v.value%2 == 0 {
            v.evenChan <- v.value
        } else {
            v.oddChan <- v.value
        }
    }
}

This function listens on serverChan in an infinite loop (or until the channel is closed).

For each message (v) received: It checks if the value (v.value) is even (v.value % 2 == 0): If even, it sends the value to the evenChan. If odd, it sends the value to the oddChan.

The Server function is a central dispatcher that routes numbers to either oddChan or evenChan depending on their classification.

4. Main Function

This is the entry point of the program, where all goroutines are set up.

Channels for Odd and Even Numbers:

oddChan := make(chan int32)
evenChan := make(chan int32)

Two channels are created, oddChan for odd numbers and evenChan for even numbers.

Slicing Arrays for Results:

odds, evens := []int32{}, []int32{}

Two slices odds and evens are initialized to store classified numbers.

WaitGroup Setup:

wg := &sync.WaitGroup{}
wg.Add(2)

A sync.WaitGroup is initialized with a count of 2 to track the two goroutines that will process numbers from oddChan and evenChan.

The program will wait for both goroutines to finish before proceeding.

5. Goroutines for Receiving and Storing Odd and Even Numbers

Odd Number Goroutine:

go func() {
    for v := range oddChan {
        odds = append(odds, v)
    }
    wg.Done()
}()

A goroutine listens on oddChan. For each value received, it appends the value to the odds slice. Once oddChan is closed (by the main goroutine), this goroutine finishes, and wg.Done() is called to signal that it’s complete.

Even Number Goroutine:

go func() {
    for v := range evenChan {
        evens = append(evens, v)
    }
    wg.Done()
}()

Similar to the odd number goroutine, this one listens on evenChan, appends values to the evens slice, and signals completion using wg.Done() once evenChan is closed.

6. Launching the Server

go Server()

7. Sending Data to the Server

go func() {
    for _, v := range list {
        serverChan <- in{v, oddChan, evenChan}
    }
    close(oddChan)
    close(evenChan)
}()

Another goroutine iterates over the list of numbers (list := []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}). For each number v in the list, it creates an in struct, containing:

It sends the in struct to the serverChan to be processed by the Server() goroutine. After all numbers have been sent, it closes both oddChan and evenChan to signal that no more data will be sent, which will eventually terminate the goroutines listening on these channels.

8. Waiting for Completion

wg.Wait()

The program waits until both goroutines (that are appending numbers to odds and evens) have finished their tasks. This is ensured by the WaitGroup.

9. Printing the Results

fmt.Println("odds")
for _, result := range odds {
    fmt.Printf("%d\n", result)
}
fmt.Println("evens")
for _, result := range evens {
    fmt.Printf("%d\n", result)
}

After all goroutines have finished, the program prints the contents of the odds and evens slices.

Key Concepts

Concurrency and Goroutines: The program uses multiple goroutines to handle tasks concurrently. One goroutine classifies numbers as odd or even (Server()), two additional goroutines append odd and even numbers to separate slices, another goroutine sends data to the server.

Channels: Channels (serverChan, oddChan, and evenChan) are used to communicate between goroutines safely without using shared memory. serverChan dispatches the numbers to be processed, oddChan and evenChan are used to collect odd and even numbers, respectively.

Synchronization: The sync.WaitGroup ensures that the main function waits for the two goroutines appending numbers to finish before printing the results.

Avoiding Deadlocks: The channels are closed (close(oddChan) and close(evenChan)) once all the data has been sent. This prevents deadlocks, ensuring that the goroutines listening on these channels terminate gracefully after processing all incoming values.

The program will print the odd and even numbers from the list:

odds
1
3
5
7
9
evens
2
4
6
8
10

Conclusion

The program effectively demonstrates how to utilize Go’s concurrency model, channels, and goroutines to process data in parallel. It classifies a list of integers into odd and even categories, and it handles communication and synchronization between concurrent tasks using channels and WaitGroup.