首先,让我开始说我知道
sync
包和它的waitgroup
选项,我不想用它来进行这个测试。我正在测试一种信号量。
所以我有:
package main
import (
"fmt"
"os"
"time"
)
func main() {
fmt.Print("wassap")
jobs := make(chan int)
processStarted := make(chan struct{}, 1)
processCompleted := make(chan struct{}, 1)
createJobs(jobs)
go func() {
worker(jobs, processStarted, processCompleted)
}()
go func() {
sync(processStarted, processCompleted)
}()
time.Sleep(3600 * time.Second)
fmt.Print("\nend of main...")
interrupt := make(chan os.Signal)
<-interrupt
}
func createJobs(jobs chan<- int) {
defer close(jobs)
for i := 1; i < 20; i++ {
jobs <- i
}
}
func worker(jobs <-chan int, processStarted <-chan struct{}, processCompleted <-chan struct{}) {
for {
select {
case i := <-jobs:
fmt.Printf("\nFetching job #%d from channel", i)
time.Sleep(2 * time.Second)
case <-processStarted:
fmt.Print("\nProcess Started. Waiting for it to be completed")
<-processCompleted
fmt.Print("\nProcess completed")
}
}
}
func sync(processStarted chan<- struct{}, processCompleted chan<- struct{}) {
// acquire semaphore. Send signal to channel to indicate that it is busy
processStarted <- struct{}{}
for i := 1; i < 5; i++ {
fmt.Printf("\nprocessing %d", i)
time.Sleep(5 * time.Second)
}
// release semaphore
processCompleted <- struct{}{}
}
我要测试的内容非常简单:我有一个
createJobs
函数,它的唯一目的是将元素添加到一个通道,在本例中是一个 int 通道。然后我有一个 worker
它将从该通道中拉出对象并在拉出下一个元素之前休眠 2 秒。
现在,还有一个同步功能。此函数的唯一目的是模拟在
worker
运行时启动的进程。如果此过程处于活动状态,则应在 jobs
结束时停止对 sync
元素的处理,这就是我有两个通道的原因,一个表示该过程开始,一个表示该过程结束。
运行我的代码时出现以下错误:
fatal error: all goroutines are asleep - deadlock!
如果我修改
createJobs
的调用方式,将其包装在这样的 goroutine 中:
go func() {
createJobs(jobs)
}()
我的代码运行正确。
我只是想了解为什么会这样。我的意思是:
main
例程正在执行,然后它调用了 createJobs
(没有包装)所以 main
例程被阻塞,直到这个调用结束。一旦createJobs
结束,就意味着频道中有元素。 main
继续执行并启动其他 goroutines worker
和 sync
来做他们的事情。在 main
结束之前,我只是添加了一个 sleeper 来给之前创建的 goroutines 时间来完成。
再说一次,这只是一个测试,我不是在问这个问题的其他解决方案,我只是想知道当
createJobs
发生在 goroutine 之外时会发生什么。
提前致谢。