Go 戈罗季斯正在睡着

Go 戈罗季斯正在睡着,go,concurrency,Go,Concurrency,我遇到了致命错误:所有goroutine都处于休眠状态-死锁,即使我正在使用缓冲通道并获得结果。但在得到所有结果后,我发现了一个错误 package main import ( "fmt" "time" ) func main() { StartJobExample() } var MAX_NUM = 1000 func StartJobExample(){ t1 := time.Now() jobs := m

我遇到了致命错误:所有goroutine都处于休眠状态-死锁,即使我正在使用缓冲通道并获得结果。但在得到所有结果后,我发现了一个错误

package main

import (
    "fmt"
    "time"
)

func main() {
    StartJobExample()
}

var MAX_NUM = 1000
func StartJobExample(){
    t1 := time.Now()
    jobs := make(chan int,MAX_NUM)
    result:=make( chan int,MAX_NUM)

    go worker(jobs,result)
    writeNums(jobs)


    for j := range result{
        fmt.Println("number read is ",j)
    }
    close(result)

   t2 := time.Now()

   fmt.Println("Time taken in operation ",t2.Sub(t1).Seconds())
}

func  worker(jobs <-chan int ,result chan<- int){
         for i:= range jobs{
                result<-addTwo(i)
         }
}

func writeNums(jobs chan<- int){
    for i:=0;i<MAX_NUM;i++{
        fmt.Println("adding job ",i)
        jobs<-i
    }
    close(jobs)
}

func addTwo(i int)int{
    return i+2
}
主程序包
进口(
“fmt”
“时间”
)
func main(){
StartJobExample()
}
var MAX_NUM=1000
func StartJobExample(){
t1:=时间。现在()
作业:=制造(成交量,最大数量)
结果:=make(chan int,MAX_NUM)
go worker(工作、结果)
写入枚举(作业)
对于j:=范围结果{
fmt.Println(“读取的数字为”,j)
}
关闭(结果)
t2:=时间。现在()
fmt.Println(“运行所用的时间”,t2.Sub(t1.Seconds())
}

func-worker(jobs您的代码中有几个错误,让我们逐一检查一下

首先,在您的案例中,您并不真正需要缓冲通道,因为它们目前正在帮助掩盖您真正的问题

其次,
writeNums
函数应该在一个单独的goroutine中执行。现在,您可以在同一goroutine中的
jobs
通道中进行写入,并从
result
通道中进行读取(在
main
goroutine中),在您的情况下,这必然会产生死锁。此问题通过使用缓冲通道来掩盖。因此,只需执行以下操作:

go writeNums(jobs)
第三,您当前的代码永远不会执行以下操作:

for j := range result{
        fmt.Println("number read is ",j)
    }
    close(result)
这就是在您的示例中产生死锁的原因。
result
通道将永远不会关闭,因为
close(result)
是在
for
循环之后执行的。您应该将此
close(result)
放在
worker
函数中,在
for
循环之后

func  worker(jobs <-chan int ,result chan<- int){
         for i:= range jobs{
                result<-addTwo(i)
         }
         close(result)
}
在本例中,您使用
sync.WaitGroup
同步所有
worker
goroutine。首先添加一个单独的goroutine,等待所有
worker
goroutine完成(
wg.Wait()
)并关闭
结果
频道

其次,在创建每个
worker
goroutine之前,需要先执行
wg.Add(1)

第三,修改
worker
函数,以便在从
jobs
通道读取作业并写入
result
通道后执行
wg.Done()


当最后一个
worker
goroutine执行
wg.Done()
wg.Wait()
将在其goroutine中取消阻止执行,并执行
close(结果)
。是一个完整的工作示例。

对于j:=范围结果
在通道
结果
关闭时中断循环。通道
结果
在循环后关闭。死锁。您最好学会使用
gofmt
。如果我通过添加
go worker(作业,结果)来增加工作人员数量
Emin的解决方案失败的次数超过1次。任何人都可以通过增加工作人员的数量来尝试它。
结果通道将永远不会关闭,因为关闭(结果)是在for循环之后执行的。您应该关闭(结果)在worker函数中,在for循环之后。
这不完全正确。程序将永远不会到达语句
close(result)
,因为程序将阻止推入
作业
,而这反过来将阻止,因为它的排水器(
worker
)将阻止推入
结果
,因为在该执行点,其排水器尚未工作。更重要的是,关闭通道意味着将不会有任何进一步的写入,并且对其进行读取可以停止。众所周知,负责写入通道的例程应负责关闭通道为了防止写封闭通道的恐慌。如果我通过添加
go-worker(作业,结果)来增加worker的数量
Emin的解决方案失败的次数超过1次。有人能通过增加工人数量来尝试吗?是的,对。有点忘记了他们被缓冲了。我已经到了提问的极限,有人能帮助增加工人数量吗。
func StartJobExample(){
    t1 := time.Now()
    numberOfWorkers := 5
    jobs := make(chan int)
    result:=make( chan int)
    var wg sync.WaitGroup

    //initialize a goroutine for syncing completion for all workers
    go func() {
      wg.Wait()
      close(result)
    }()
    
    //initialize all workers
    for i :=0; i < numberOfWorkers; i++ {
      wg.Add(1)
      go worker(&wg, jobs, result, i)
    }

// rest of the StartExample function is unchanged
// ...
}

func  worker(wg *sync.WaitGroup, jobs <-chan int ,result chan<- int, num int){
    for i:= range jobs{
           result<-addTwo(i)
    }
    wg.Done()
    fmt.Println("closing worker ", num)
}