我要走了,所以这可能是一个愚蠢的问题。
我似乎无法弄清楚为什么我的一个go例程被另一个例程阻塞了。我的理解(可能是错误的)go例程作为独立的轻量级线程运行,因此除非我搞砸了,否则它们不应互相阻塞:)
我粘贴了以下代码,希望能帮助您解决此问题。
package main
import "fmt"
import "time"
import "sync"
func worker( jobs <-chan int, job2 chan<- int) {
defer wg.Done()
for j := range jobs {
fmt.Println("finished job", j)
time.Sleep(time.Second/2)
if(j%3==0){
job2 <- j
}
}
close(job2)
fmt.Println("channel job2 closed")
}
func worker2(job2 <-chan int) {
defer wg.Done()
for i:= range job2 {
fmt.Println(i)
time.Sleep(time.Second*10)
}
}
var wg sync.WaitGroup
func main() {
wg.Add(2)
jobs := make(chan int)
job2 := make(chan int)
go func() {
for j := 1; j <= 10; j++ {
jobs <- j
}
close(jobs)
fmt.Println("channel jobs closed")
}()
go worker(jobs,job2)
go worker2(job2)
wg.Wait()
fmt.Println("exiting main")
}
运行此代码时,我得到以下输出
finished job 1
finished job 2
finished job 3
finished job 4
3
finished job 5
finished job 6
6
finished job 7
finished job 8
finished job 9
9
finished job 10
channel jobs closed
channel job2 closed
exiting main
但是我期待这样的事情吗?
finished job 1
finished job 2
finished job 3
finished job 4
3
finished job 5
finished job 6
finished job 7
finished job 8
finished job 9
finished job 10
channel jobs closed
6
9
channel job2 closed
exiting main
答案 0 :(得分:3)
您的例程属于某种阻塞,因为未缓冲通道。在无缓冲通道上进行写/读是一项阻塞操作。因此,根据定义,您的例程必须彼此等待。
从本质上讲,您半秒钟的睡眠是无关紧要的,因为第二个工人睡眠10秒钟。那10秒将阻止对第二个通道的读取/写入。向该通道添加缓冲区以解决此问题。
我想指出的其他一些事情是:
time.Sleep(time.Second/2)
无法正常工作(嗯,可以,但是例如除以3则无效)。 time.Sleep
需要一个time.Duration
参数,即int64
。您需要传递类似time.Millisecond * 500
的内容import "package"
,只需使用import ( "package1"\n"package2")
context.Context
和select
构造。您可以创建一个context.WithCancel
,然后在所有例程中选择监听ctx.Done()
。然后,您可以一口气取消所有例程,而不必处理信号并将内容推送到取消通道上我已经做了几件事(主要是创建频道,以及一些次要的代码清理),并创建了一个游乐场示例here