@hollowaykeanho Thanks
I’m rethinking this with four scenarios and let me if this makes any sense to you.
-
case1: one way communication (from main to goroutine only).
- create m workers
- assign n jobs
- main won’t terminate until all goroutines get all jobs done
- I’d like to use
sync.WaitGroup{}
to sync up between main and goroutines
-
case2: one way communication but for any job that exceeds some preset time it times out and get ignored
- instead of
wg
, I’d like to use a dedicated channel for goroutines to notify main whenever it get the job done. on main I’d like to use select
to choose between this channel and a preset timer to achieve this time out function
- use
for
loop with same number of iteration as number of jobs to sync up between main and goroutine
-
case3: two way communication (main send jobs to goroutines and goroutines send results back to main)
- create n jobs
- make these buffered channels with size of
n - m
to avoid dead lock
- make another channel for goroutine to send result back to main
- create m workers
- assign n jobs
-
close(job)
to notify goroutines
- use
for
loop with same number of iteration as number of jobs to receive result of each job from goroutines
- at goroutine, use
for ... range...
to keep receiving jobs, do jobs, send result back to main, until get notified that job close
- bascally, use result channel to sync up main and goroutines
-
case4: two way communication with time limit that main time out any result from goroutines if that job isn’t done on time
- use
for
loop with same number of iteration as number of jobs
- use
select
to choose between result from goroutine and a timer
- basically, use the result channel to sync up between main and goroutines
below are codes for each cases.
//case1:
// workers: m
// jobs: n
// no response is required from goroutine back to main
// main won't terminate until all goroutines finish jobs
// use sync.WaitGroup
package main
import (
"fmt"
"strconv"
"sync"
"time"
)
const numberOfWorkers = 3
const numberOfJobs = 5
func worker(id int, job chan string, wg *sync.WaitGroup) {
defer wg.Done()
for receivedJob := range job {
fmt.Printf("worker %d received %s. working\n", id, receivedJob)
time.Sleep(2*time.Second)
fmt.Printf("worker %d get %s done.\n", id, receivedJob)
}
}
func main() {
wg := sync.WaitGroup{}
wg.Add(numberOfWorkers)
job := make(chan string)
for w := 0; w < numberOfWorkers; w++ {
fmt.Printf("created worker %d\n",w)
go worker(w, job, &wg)
}
for j := 0; j < numberOfJobs; j++ {
fmt.Printf("assigned job %d\n", j)
job <- "job " + strconv.Itoa(j)
}
close(job)
wg.Wait()
}
//case2
// workers: m
// jobs: n
// no response is required from goroutine back to main
// main won't terminate until all goroutines finish jobs
// except the processing of each job by goroutine exceed preset timer
// ues channel + select + time.After to control this
package main
import (
"fmt"
"strconv"
"time"
)
const numberOfWorkers = 3
const numberOfJobs = 5
func worker(id int, job chan string, done chan bool) {
for receivedJob := range job {
fmt.Printf("worker %d received %s. working\n", id, receivedJob)
time.Sleep(1*time.Second)
fmt.Printf("worker %d get %s done.\n", id, receivedJob)
done <-true
}
}
func main() {
job := make(chan string, 2)
done := make(chan bool)
for w := 0; w < numberOfWorkers; w++ {
fmt.Printf("created worker %d\n",w)
go worker(w, job, done)
}
for j := 0; j < numberOfJobs; j++ {
fmt.Printf("assigned job %d\n", j)
job <- "job " + strconv.Itoa(j)
}
close(job)
for r := 0; r < numberOfJobs; r++ {
select {
case <-done:
fmt.Println("one job done on time")
case <-time.After(2*time.Second):
fmt.Println("time out")
}
}
}
//case3
// workers: m
// jobs: n
// require goroutine send result of each job back to main
// use 2nd channel to send result from goroutine back to main
// use for loop to iterate same number of loops as number of jobs
// to sync up with goroutine
package main
import (
"fmt"
"strconv"
"time"
)
const numberOfWorkers = 3
const numberOfJobs = 5
func worker(id int, job chan string, result chan string) {
for receivedJob := range job {
fmt.Printf("worker %d received %s. working\n", id, receivedJob)
time.Sleep(1*time.Second)
result <-receivedJob + " done by worker " + strconv.Itoa(id)
fmt.Printf("worker %d get %s done.\n", id, receivedJob)
}
}
func main() {
job := make(chan string, numberOfJobs)
result := make(chan string)
for w := 0; w < numberOfWorkers; w++ {
fmt.Printf("created worker %d\n",w)
go worker(w, job, result)
}
for j := 0; j < numberOfJobs; j++ {
fmt.Printf("assigned job %d\n", j)
job <- "job " + strconv.Itoa(j)
}
close(job)
for r := 0; r < numberOfJobs; r++ {
received := <-result
fmt.Printf("received result %d : %s\n", r, received)
}
}
//case4:
// workers: m
// jobs: n
// require goroutine send result of each job back to main
// if main can't receive job in preset time then main get it
// times out and ignore it
// use 2nd channel to send result from goroutine back to main
// use for loop + select + time.After() to sync up with goroutine
package main
import (
"fmt"
"strconv"
"time"
)
const numberOfWorkers = 3
const numberOfJobs = 5
func worker(id int, job chan string, result chan string) {
for receivedJob := range job {
fmt.Printf("worker %d received %s. working\n", id, receivedJob)
time.Sleep(2*time.Second)
result <-receivedJob + " done by worker " + strconv.Itoa(id)
fmt.Printf("worker %d get %s done.\n", id, receivedJob)
}
}
func main() {
job := make(chan string, 2)
result := make(chan string)
for w := 0; w < numberOfWorkers; w++ {
fmt.Printf("created worker %d\n",w)
go worker(w, job, result)
}
for j := 0; j < numberOfJobs; j++ {
fmt.Printf("assigned job %d\n", j)
job <- "job " + strconv.Itoa(j)
}
close(job)
for r := 0; r < numberOfJobs; r++ {
select {
case received := <-result:
fmt.Printf("received result %d : %s\n", r, received)
case <-time.After(3*time.Second):
fmt.Printf("time out\n")
}
}
}
Thanks