|
If 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 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
|
This can be fixed with a mutex.
Now that we've got working code (with the mutex), we have to ask: have we proved Chris wrong? I don't think so. Chris never said it's impossible to implement this in Go. Chris just said that implementing it in Go is uglier than using an array of promises in some other language. And I think this code is uglier than an array of promises.
Although I think I disagree with Chris. He says that an array of channels is significantly uglier than an array of promises. I don't think so. I think an array of channels is fine (and is easier to understand than the signal, signalCount, computed, consumed, +mutex code).