New gopher here. The following code works for me, but I'm confused by the doStuff function. Why is it true that the ac variable is of type chan time.Duration, rather than chan chan time.Duration?
package main
import (
"log"
"sync"
"time"
)
// the function to be run inside a goroutine. It receives a channel on ch, sleeps for t, then sends t
// on the channel it received
func doStuff(t time.Duration, ch <-chan chan time.Duration) {
ac := <-ch
time.Sleep(t)
ac <- t
}
func main() {
// create the channel-over-channel type
sendCh := make(chan chan time.Duration)
recvCh := make(chan time.Duration)
// use this to block until all goroutines have received the ack and logged
var wg sync.WaitGroup
// start up 10 doStuff goroutines
for i := 0; i < 10; i++ {
go doStuff(time.Duration(i+1)*time.Second, sendCh)
// send channels to each doStuff goroutine. doStuff will "ack" by sending its sleep time back
sendCh <- recvCh
wg.Add(1)
go func() {
defer wg.Done()
log.Printf("slept for %s", <-recvCh)
}()
}
wg.Wait()
}
What is ac := <- ch doing, and why does ac <- t work?
The first thing I tried was to just remove the ac variable because it at first seemed like an unnecessary extra step, but doing this causes the output to be sequential rather than concurrent:
func doStuff(t time.Duration, ch <-chan chan time.Duration) {
time.Sleep(t)
<- ch <- t
}
So I started experimenting, to me it seems like it's just initializing a new variable as a copy of the argument sendCh, which is an empty chan chan time.Duration. so I tried the following:
func doStuff(t time.Duration, ch <-chan chan time.Duration) {
// What makes this different from the original code?
ac := make(chan chan time.Duration)
time.Sleep(t)
ac <- t
}
// This gives an immediate error: cannot use t (type time.Duration) as type chan time.Duration in send
Okay, that makes sense. I can't send a time.Duration to a channel of channels of time.Duration, I need to send a channel of time.Duration. Gotcha... but I don't know why the original code works, since it seems to me this should have been the same aside from the original being a receive only channel. So I imported fmt and checked the type of ac, and sure enough its a chan time.Duration. Why?
My final experiment was to try initializing ac as a chan time.Duration directly, which caused deadlock:
func doStuff(t time.Duration, ch <-chan chan time.Duration) {
ac := make(chan time.Duration)
time.Sleep(t)
ac <- t
// this causes deadlock
}
What the heck lol... So, to summarize, I don't understand why in the original code ac := <- ch causes it to be initialized as a channel of time.Duration rather than a channel of channels of time.Duration, and I don't understand why the changes I made in the experiments caused the different error conditions that they did. Any insight appreciated!