The following code ends with a fatal error: all goroutines are asleep - deadlock!
// Package letter returns the frequency of letters in texts using parallel computation.
package letter
import "fmt"
const testVersion = 1
type FreqMap map[rune]int
func Frequency(s string) FreqMap {
m := FreqMap{}
for _, r := range s {
m[r]++
}
return m
}
func ConcurrentFrequency(l []string) FreqMap {
ch := make(chan FreqMap)
for _, s := range l {
go func() {
ch <- Frequency(s)
}()
}
m := FreqMap{}
for c := range ch {
fmt.Println("channel:", c)
for k, v := range c {
m[k] += v
}
}
return m
}
This is output:
channel: map[121:8 101:42 98:8 104:28 102:6 71:1 59:1 97:33 110:15 103:15 112:6 109:5 116:38 10:7 87:2 107:1 108:17 99:3 117:7 39:5 79:4 114:27 105:15 44:7 119:8 100:12 63:2 65:1 118:3 45:1 32:72 111:18 115:24]
channel: map[97:33 110:15 111:18 117:7 108:17 45:1 115:24 10:7 79:4 32:72 121:8 100:12 105:15 63:2 107:1 71:1 119:8 114:27 103:15 102:6 65:1 44:7 87:2 118:3 101:42 98:8 116:38 39:5 112:6 104:28 109:5 99:3 59:1]
channel: map[99:3 116:38 104:28 108:17 44:7 117:7 119:8 114:27 10:7 87:2 110:15 100:12 103:15 107:1 32:72 111:18 102:6 59:1 45:1 101:42 109:5 63:2 115:24 97:33 105:15 112:6 65:1 71:1 79:4 121:8 98:8 39:5 118:3]
fatal error: all goroutines are asleep - deadlock!
My understanding is that range waits for data from channel until the channel is closed, but adding close(ch) inside the for loop, or inside the func() or after those, make things worse (the fmt.Println does not get anything) - tried also with defer (same problem)
What would be the correct approach? Isn't range the right solution in this case ?
Thanks a lot !
The range keyword can also be used on a channel. By doing so, it will iterate over every item thats send on the channel. You can iterate on both buffered and unbuffered channels, but buffered channels need to be closed before iterating over them.
A deadlock happens when a group of goroutines are waiting for each other and none of them is able to proceed. For example: When one goroutine try to receive message from channel. And channel is empty.
Range only stops when the channel is closed. You're hitting a deadlock because nothing is writing to the channel, but you're sitting waiting for something to be written. You could add a sync.WaitGroup
and close the channel after all of the goroutines writing to it have finished.
You should probably also change the loop as there is potential for the wrong values to be passed because you're closing over the loop variable which can change concurrently; this will be more reliable:
for _, s := range l {
go func(s rune) {
ch <- Frequency(s)
}(s)
}
I would prefer to use for...select to receive the message in channel.
func main() {
in := State{[]What{A,B,C,D},[]What{},nil}
out := make(chan State)
go in.think(out)
life:=5
for {
select {
case s:=<-out:
fmt.Printf("out : %+v\n", s)
default:
time.Sleep(50 * time.Millisecond)
if life--;life==0 {
return
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With