Im learning Go channels and I don't know how to implement this program

Issue

Let’s say I have 2 channels-senders which are sending numbers to one channel-receiver. First channel-sender sends numbers from 0 and another channel-sender sends numbers from 11. Channel-receiver receives data and sends it to one of the 2 channels-printers. First channel-printer receives even numbers and other one receives odd numbers. Printers should store numbers and print the data when work is finished. Work should end when channel-receiver receives and sends 20 numbers to printers.

var count = 0
func main() {

sender1 := make(chan int)
sender2 := make(chan int)

x := 0
y := 11
for x <= 20{
        var numx = x
        x++
        var numy = y
        y++
        go sender(sender1, numx)
        go sender(sender2, numy)
    }
}
func sender(receiver chan<- int, x int) {
if count >= 20 {
    fmt.Println("limit has been reached")
}
count++
receiver <- x
//even, else odd
if x % 2 == 0{
    fmt.Println("even")
} else {
    fmt.Println("odd")
}
}

That’s what I’ve got so far and I have no clue what to do next and how to handle this situation.

Solution

So, if I’m interpreting your program correctly, this program should work.

So, There are two senders:

  • Sender 1 sends: 0, 1, 2, …
  • Sender 2 sends: 11, 12, 13, …

The sender now sends it to a receiver which listens for 20 numbers in total and then stops (Instructs sender and receiver to stop as well).

It’s the receiver’s duty to relay the data received from the sender goroutines to the printers.

There are two printers:

  • Printer 1 receives odd numbers and prints them
  • Printer 2 receives even numbers and prints them
sender (2 instance) -> mediator (1 instance) -> printer (2 instance)
package main

import (
    "fmt"
    "sync"
)

type packet struct {
    send     chan int
    recvOdd  chan int
    recvEven chan int
    closed   chan struct{}
}

func safeClose(ch chan int) {
    _, ok := <-ch
    if !ok {
        return
    }
    close(ch)
}

// sender spawns multiple goroutines and keeps on
// sending numbers continuously in serial order until
// p.closed is closed. The goroutines have their own
// starting point.
// Example start = [0, 11]
// sender will send it in this order:
// go -> 0, 1, 2, 3 ...  // "go" keyword means goroutine
// go -> 11, 12, 13, ... // "go" keyword means goroutine
func (p *packet) sender(wg *sync.WaitGroup, start ...int) {
    wg.Add(len(start))
    for _, sp := range start {
        // Spawn!
        go func(s int, w *sync.WaitGroup) {
            defer w.Done()
            // Start from "s", keep on incrementing
            for num := s; ; num++ {
                select {
                // I'm done. Return
                case <-p.closed:
                    return
                // Send
                case p.send <- num:
                }
            }
        }(sp, wg)
    }
}

// mediator receives upto a limit and then
// signals to close down. It also judges
// if the number received is even/ odd and
// sends to the respective channel.
func (p *packet) mediator(limit int) {
    for i := 1; i <= limit; i++ {
        r := <-p.send
        if r%2 == 0 {
            p.recvEven <- r
        } else {
            p.recvOdd <- r
        }
    }
    // close down the channels.
    p.close()
}

// close all channels except the send channel
// as there's a possibility that that send's goroutines
// might send to the closed channel which would cause panic.
// So, let send close the p.send channel.
func (p *packet) close() {
    close(p.closed)
    close(p.recvOdd)
    close(p.recvEven)
}

// printer receives from printer
// and then stores it and prints it.
func (p *packet) printer() {
    var odd, even = make(chan []int), make(chan []int)
    go recv(odd, p.recvOdd)
    go recv(even, p.recvEven)
    oBuf, eBuf := <-odd, <-even
    fmt.Println(oBuf)
    fmt.Println(eBuf)
}

// recv just receives and keeps on bufferring.
// When finished receiving, it sends the buffer
// to res.
func recv(res chan<- []int, ch <-chan int) {
    var buffer = make([]int, 0)
    for c := range ch {
        buffer = append(buffer, c)
    }
    res <- buffer
}

func main() {
    // Declare and init a packet
    var p packet
    {
        p.closed = make(chan struct{})
        p.send = make(chan int, 1)
        p.recvEven = make(chan int, 1)
        p.recvOdd = make(chan int, 1)
    }
    defer close(p.send)

    var wg sync.WaitGroup
    defer wg.Wait()

    // Setup a sender which sends values to the mediator.
    // Internally it'll spawn two goroutines. One starts from 0,
    // and the other from 11. Could be extended as well.
    p.sender(&wg, 0, 11)
    // Setup a mediator that mediates the data from sender
    // to printer. Only sends 20 number of data.
    go p.mediator(20)
    // Wait for the printer to print and then return.
    p.printer()
}

Answered By – shmsr

Answer Checked By – Gilberto Lyons (GoLangFix Admin)

Leave a Reply

Your email address will not be published.