多次运行同一个 go 程序会引发恐慌:在关闭的通道上发送

我是 golang 的新手,并试图了解 workerpool 的工作原理。如果我运行一次并且尝试多次运行我会感到恐慌,则以下示例程序可以正常工作:发送关闭通道错误。Go 版本是 go1.14.2


package main

import (

    "fmt"

    "time"

)

func main() {

    jobs := make(chan int, 10)

    results := make(chan int, 10)


    for x := 1; x <= 3; x++ {

        go worker(x, jobs, results)

    }


    for j := 1; j <= 6; j++ {

        jobs <- j

    }

    close(jobs)

    for r:=range results{

        fmt.Println("Result received from worker: ", r)

    }

}

func worker(ID int, jobs <-chan int, results chan<- int) {

    for job := range jobs {

        fmt.Println("Worker ", ID, " is working on job ", job)

        time.Sleep(1000*time.Millisecond)

        fmt.Println("Worker ", ID, " completed work on job ", job)

        results <- job

    }

    close(results)

}

第一次运行没问题


go run main.go                                                                            

Worker  3  is working on job  1

Worker  1  is working on job  2

Worker  2  is working on job  3

Worker  2  completed work on job  3

Worker  2  is working on job  4

Result received from worker:  3

Worker  1  completed work on job  2

Worker  1  is working on job  5

Result received from worker:  2

Worker  3  completed work on job  1

Worker  3  is working on job  6

Result received from worker:  1

Worker  3  completed work on job  6

Result received from worker:  6

第二次运行给出了这个。


Worker  3  is working on job  2

Worker  2  is working on job  3

Worker  1  is working on job  1

Worker  3  completed work on job  2

Worker  3  is working on job  4

Worker  2  completed work on job  3

Worker  2  is working on job  5

Worker  1  completed work on job  1

Worker  1  is working on job  6

Result received from worker:  2

Result received from worker:  3

Result received from worker:  1

Worker  1  completed work on job  6

Worker  3  completed work on job  4

Result received from worker:  6

panic: send on closed channel


谁能帮我理解发生了什么?


皈依舞
浏览 181回答 2
2回答

临摹微笑

您有多个关闭results通道的 goroutine。func worker(ID int, jobs <-chan int, results chan<- int) {&nbsp; &nbsp; for job := range jobs {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Worker ", ID, " is working on job ", job)&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(1000*time.Millisecond)&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Worker ", ID, " completed work on job ", job)&nbsp; &nbsp; &nbsp; &nbsp; results <- job&nbsp; &nbsp; }&nbsp; &nbsp; close(results)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <<<<-------- Here}worker你在三个不同的并发 goroutine 中运行这个函数。第一个到达标记线的人关闭通道,其他人尝试results <- job在循环中的关闭通道上发送。

眼眸繁星

Eli Bendersky 的回答描述了这个问题。这个答案描述了修复。我知道你没有要求修复,但我假设你有兴趣。所以就在这里。修复方法是在关闭通道之前等待工作 goroutine 完成。使用sync.WaitGroup来实现等待。var wg sync.WaitGroupfor x := 1; x <= 3; x++ {&nbsp; &nbsp; wg.Add(1)&nbsp; // increment worker counter&nbsp; &nbsp; go func(x int) {&nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done() // decrement on return from goroutine&nbsp; &nbsp; &nbsp; &nbsp; worker(x, jobs, results)&nbsp; &nbsp; }(x)}// Close results channel when workers are done.go func() {&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(results)}()在 PlayGround 上运行这个 GoLANG 程序:https: //play.golang.org/p/GM-0Gqx0Gbg
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go