Go语言 由于在开放通道上测距而发生僵局,但没有引发恐慌

jgwigjjp  于 2023-08-01  发布在  Go
关注(0)|答案(2)|浏览(85)

我故意写了这样一段代码来引起死锁和随后的恐慌抛出:

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("Start:", time.Now())
    channel1 := make(chan string, 2)

    channel1 <- "Cat"
    channel1 <- "Dog"

    limiter := time.NewTicker(time.Millisecond * 500)
    for channel1Item := range channel1 {
        <-limiter.C
        fmt.Println(channel1Item)
    }

    fmt.Println("End:", time.Now())
}

字符串
在某种程度上,死锁确实会发生,代码只是无限期地挂起,但是,它不会引发恐慌。如果我删除限制器(股票代码),它就会这样做。为什么自动收报机能防止恐慌被抛出?
我目前正在学习Go,当我改变随机位以满足我的好奇心时,我无意中遇到了这个例子。奇怪的行为(一个恐慌不被抛出)发生在我决定不关闭通道,看看会发生什么。
我知道在一个没有被馈送的开放通道上测距通常会引发恐慌,但似乎在循环中有一个自动收报机会中断恐慌引发行为。

yuvru6vn

yuvru6vn1#

因为GO中的判断是,当一个goroutine试图在一个封闭的通道上发送一条有价值的消息时,它会触发恐慌。
在您的代码中,您没有关闭channel 1,因此循环将无限期地等待channel 1接受该值。<-限制器。C会周期性地向通道发送值因此channel 1不会排除panic,带有限制器的循环将挂起即使他没有任何新值
希望能对你有所帮助

sh7euo9m

sh7euo9m2#

我知道在一个没有被喂食的开放通道上测距通常会引发恐慌
我猜这是正确的,如果“在开放通道上测距”是唯一发生的事情(或者所有其他goroutine也被阻塞),就会检测到死锁(并触发恐慌)。将在此(playground)中检测到死锁:

func main() {
    c := make(chan int)
    for _ = range c {
    }
}

字符串
但不是在这个(playground)中:

func main() {
    go func() {
        for {
            time.Sleep(time.Nanosecond)
        }
    }()

    c := make(chan int)
    for _ = range c {
    }
}


这是因为,当for _ = range c {被阻塞时,goroutine没有阻塞(所以没有死锁)。
识别死锁的代码相对简单,如果没有任何东西可以运行,就会触发死机。它不会检查正在运行的代码是否在做有用的事情!
根据Ticker的文档:
自动收报机将调整时间间隔或下降滴答,以弥补缓慢的接收器。
无论频道上是否有监听,自动收报机都将继续运行;这类似于在代码中添加以下内容(playground):

channel2 := make(chan time.Time, 1)
go func() {
    for {
        time.Sleep(time.Millisecond * 500)
        select {
        case channel2 <- time.Now():
        default:
        }
    }
}()


无论channel2上是否有监听对象,这个循环都会继续运行。因此,不会检测到死锁(也不会触发死机)。添加Ticker具有相同的影响; X1 M3 N1 X正在运行的事实意味着将不会检测到死锁。

相关问题