Golang:当填充通道的函数调用未嵌入 goroutine 时,为什么我会遇到死锁

问题描述 投票:0回答:0

首先,让我开始说我知道

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 之外时会发生什么。

提前致谢。

go parallel-processing channel goroutine
© www.soinside.com 2019 - 2024. All rights reserved.