7 ms·
Isn't it even simpler in Go? No channels necessary, Each goroutine gets an index or slice, and writes the results to a shared array. All you need is the gorout
by pbnjay 2y ago
Isn't it even simpler in Go? No channels necessary, Each goroutine gets an index or slice, and writes the results to a shared array.
All you need is the goroutines to report when done via a WaitGroup.
- teraflop 2y agoThat doesn't satisfy the "report the results as they become available" requirement. The desired behavior is that printing the first result should only wait for the first result to be available, not for all the results to be available.
- pbnjay 2y agoWould be trivial to show the results live though, especially for atomic values: https://go.dev/play/p/PRzzO_skWoJ https://go.dev/play/p/PRzzO_skWoJ
- valleyer 2y agoThat's not "live"; that's just polling.
- lenkite 2y agoModified the above to https://go.dev/play/p/DRXyvRHsuAH https://go.dev/play/p/DRXyvRHsuAH You get the first result in results[0] thanks to `atomic.Int32`. package main import ( "fmt" "math/rand" "sync/atomic" "time" ) func main() { args := []int{5, 2, 4, 1, 8} var indexGen atomic.Int32 indexGen.Store(-1) results := make([]int, len(args)) finished := make(chan bool) slowSquare := func(arg int, index int) { randomMilliseconds := rand.Intn(1000) blockDuration := time.Duration(randomMilliseconds) * time.Millisecond fmt.Printf("Squaring %d, Blocking for %d milliseconds...\n", arg, randomMilliseconds) <-time.After(blockDuration) idx := indexGen.Add(1) results[idx] = arg * arg fmt.Printf("Squared %d: results[%d]=%d\n", arg, idx, results[idx]) finished <- true } prettyPrinter := func() { for range time.NewTicker(time.Second).C { fmt.Println("Results: ", results) } } go prettyPrinter() for idx, x := range args { go slowSquare(x, idx) } <-finished fmt.Println("First Result: ", results[0]) fmt.Println("So-far Results: ", results) }
- Thorrez 2y agoThis will wait up to 1 second before showing a result when a result comes in. I'm pretty sure Chris doesn't want any waiting like that. This will also print some results multiple times. I think Chris wants to print each result once.
- lenkite 2y agoIt is utterly clear that the random wait is not intrinsic to the logic - it was only added for demonstration to simulate varying duration of requests. You can simply comment out the println and just pick the first results[0]. Again, the repeated println for all results was only added for demonstrative clarity. Frankly, the above satisfies all primary goals. The rest is just nitpicking - without a formal specification of the problem one can argue all day.
- Thorrez 2y ago>It is utterly clear that the random wait is not intrinsic to the logic - it was only added for demonstration to simulate varying duration of requests. I wasn't talking about the random wait at all. I was talking about for range time.NewTicker(time.Second).C { fmt.Println("Results: ", results) } >You can simply comment out the println and just pick the first results[0]. When should we look at results[0]? There needs to be some notification that results[0] is ready to be looked at. Similarly with all the rest of the results. >Frankly, the above satisfies all primary goals. The rest is just nitpicking - without a formal specification of the problem one can argue all day. I guess we have to disagree. From my reading of the blog post it was pretty clear what Chris wanted, and the code you provided didn't meet that.
- lenkite 2y agoYou 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]) }