Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to make Go channel worker have different result's length?

I made some edits from the gobyexample:

import (
    "fmt"
    "math/rand"
    "time"
)

type DemoResult struct {
    Name string
    Rate int
}

func random(min, max int) int {
    rand.Seed(time.Now().UTC().UnixNano())
    return rand.Intn(max-min) + min
}

func worker(id int, jobs <-chan int, results chan<- DemoResult) {
    for j := range jobs {
        fmt.Println("worker", id, "started  job", j)
        time.Sleep(time.Second)
        fmt.Println("worker", id, "finished job", j)
        myrand := random(1, 4)
        if myrand == 2 {
            results <- DemoResult{Name: "succ", Rate: j}
        }
        //  else {
        //  results <- DemoResult{Name: "failed", Rate: 999}
        // }
    }
}

func main() {
    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan DemoResult)
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }
    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    for a := 1; a <= numJobs; a++ {
        out := <-results
        if out.Name == "succ" {
            fmt.Printf("%v\n", out)
        }
    }
}

I commented the following code intentional to make it stuck forever:

        //  else {
        //  results <- DemoResult{Name: "failed", Rate: 999}
        // }

It seems like we should make the result’s length the same as jobs’. I was wondering if we could make it have different length?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

I was wondering if we could make it have different length?

Absolutely but you need some way of determining when you have reached the end of the results. This is the reason your example fails – currently the function assumes there will be numJobs (one result per job) results and waits for that many.

An alternative would be to use the channels closure to indicate this i.e. (playground)

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

type DemoResult struct {
    Name string
    Rate int
}

func random(min, max int) int {
    rand.Seed(time.Now().UTC().UnixNano())
    return rand.Intn(max-min) + min
}

func worker(id int, jobs <-chan int, results chan<- DemoResult) {
    for j := range jobs {
        fmt.Println("worker", id, "started  job", j)
        time.Sleep(time.Second)
        fmt.Println("worker", id, "finished job", j)
        myrand := random(1, 4)
        if myrand == 2 {
            results <- DemoResult{Name: "succ", Rate: j}
        } // else {
        //  results <- DemoResult{Name: "failed", Rate: 999}
        //}
    }
}

func main() {
    const numWorkers = 3
    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan DemoResult)

    var wg sync.WaitGroup
    wg.Add(numWorkers)
    for w := 1; w <= numWorkers; w++ {
        go func() {
            worker(w, jobs, results)
            wg.Done()
        }()
    }
    go func() {
        wg.Wait() // Wait for go routines to complete then close results channel
        close(results)
    }()

    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    for out := range results {
        if out.Name == "succ" {
            fmt.Printf("%v\n", out)
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading