4 ms·
You can completely ignore that pretty print function as it not essential to the goal. Revised example without pretty-print at https://go.dev/play/p/LkAT_g95BLO
by lenkite 2y ago
You can completely ignore that pretty print function as it not essential to the goal.
Revised example without pretty-print at https://go.dev/play/p/LkAT_g95BLO https://go.dev/play/p/LkAT_g95BLO
As soon as you have completed `<-finished` in the main go-routine, it means `results[0]` has been populated and is ready for read.
If you want to wait till all results are available, then perform `<-finished`, `len(results)` times. (Or use sync.WaitGroup)
package main
import (
"fmt"
"math/rand"
"sync/atomic"
"time"
)
func main() {
args := []int{5, 2, 4, 1, 8}
var resultCount atomic.Int32
resultCount.Store(-1)
results := make([]int, len(args))
finished := make(chan bool, len(args))
slowSquare := func(arg int, fnNum int) {
randomMilliseconds := rand.Intn(1000)
blockDuration := time.Duration(randomMilliseconds) * time.Millisecond
fmt.Printf("(#%d) Squaring %d, Blocking for %d milliseconds...\n", fnNum, arg, randomMilliseconds)
<-time.After(blockDuration)
resultIndex := resultCount.Add(1)
results[resultIndex] = arg * arg
fmt.Printf("(#%d) Squared %d: results[%d]=%d\n", fnNum, arg, resultIndex, results[resultIndex])
finished <- true
}
for i, x := range args {
go slowSquare(x, i)
}
fmt.Println("(main) Waiting for first finish")
<-finished
fmt.Println("(main) First Result: ", results[0])
}
- Thorrez 2y agoChris wants to report the results in the same order as the inputs. So 25, 4, 16, 1, 64. Your code will report the results in an arbitrary order.
- lenkite 2y agoOk, but that is even more simpler and shorter with plain `sync.WaitGroup`. package main import ( "fmt" "math/rand" "sync" "time" ) func main() { args := []int{5, 2, 4, 1, 8} results := make([]int, len(args)) var wg sync.WaitGroup slowSquare := func(arg int, resultIndex int) { randomMilliseconds := rand.Intn(1000) blockDuration := time.Duration(randomMilliseconds) * time.Millisecond fmt.Printf("(#%d) Squaring %d, Blocking for %d milliseconds...\n", resultIndex, arg, randomMilliseconds) <-time.After(blockDuration) results[resultIndex] = arg * arg fmt.Printf("(#%d) Squared %d: results[%d]=%d\n", resultIndex, arg, resultIndex, results[resultIndex]) wg.Done() } for i, x := range args { wg.Add(1) go slowSquare(x, i) } fmt.Println("(main) Waiting for all to finish") wg.Wait() fmt.Println("(main) Results: ", results) } (main) Waiting for all to finish (#4) Squaring 8, Blocking for 574 milliseconds... (#1) Squaring 2, Blocking for 998 milliseconds... (#2) Squaring 4, Blocking for 197 milliseconds... (#3) Squaring 1, Blocking for 542 milliseconds... (#0) Squaring 5, Blocking for 12 milliseconds... (#0) Squared 5: results[0]=25 (#2) Squared 4: results[2]=16 (#3) Squared 1: results[3]=1 (#4) Squared 8: results[4]=64 (#1) Squared 2: results[1]=4 (main) Results: [25 4 16 1 64]
- Thorrez 2y agoAs soon as results[0] is ready he wants to print it. Then as soon as results[1] is read he wants to print it. Etc. Not waiting till the end to print everything, and not printing anything out of order.
- lenkite 2y agoIf results[i] must be printed only AFTER print of results[0]...results[i-1], then you effectively need to wait for max of (time to compute results[0]...results[i]), since even if results[i] is computed earlier you can't print it out if results[0]..results[i-1] are not available. If result[0] takes the longest compute time, then you will definitely need to wait till the end. Frankly, a simple sequential for loop seems to the simplest solution here :) Anyways, I think this: https://go.dev/play/p/lFBpzUVVzUj https://go.dev/play/p/lFBpzUVVzUj satisfies all the constraints. Only look at the output with the "(main)" prefix, the other prints are for elucidation. package main import ( "fmt" "math/rand" "time" ) type Result struct { value int computed bool consumed bool } func main() { args := []int{5, 2, 4, 1, 8} results := make([]Result, len(args)) signal := make(chan bool) signalCount := 0 slowSquare := func(arg int, index int) { randomMilliseconds := rand.Intn(1000) blockDuration := time.Duration(randomMilliseconds) * time.Millisecond <-time.After(blockDuration) square := arg * arg results[index] = Result{value: square, computed: true} fmt.Printf("(#%d) Squared %d, index=%d, result=%2d, duration=%s, sending signal. \n", index, arg, index, square, blockDuration) signal <- true } for i, x := range args { go slowSquare(x, i) } for { if signalCount == len(results) { break } <-signal signalCount++ for i := 0; i < len(results); i++ { if !results[i].computed { break } if !results[i].consumed { fmt.Printf("(main) Squared %d, index=%d, result=%2d\n", args[i], i, results[i].value) results[i].consumed = true } } } } Example Output (#0) Squared 5, index=0, result=25, duration=8ms, sending signal. (main) Squared 5, index=0, result=25 (#4) Squared 8, index=4, result=64, duration=210ms, sending signal. (#1) Squared 2, index=1, result= 4, duration=777ms, sending signal. (main) Squared 2, index=1, result= 4 (#3) Squared 1, index=3, result= 1, duration=867ms, sending signal. (#2) Squared 4, index=2, result=16, duration=924ms, sending signal. (main) Squared 4, index=2, result=16 (main) Squared 1, index=3, result= 1 (main) Squared 8, index=4, result=64