Golang Go语言中两份代码对比,为什么第一份代码不会panic,第二份代码会panic

发布于 1周前 作者 ionicwang 来自 Go语言

第一份代码如下

package main

import ( “fmt” “time” )

func main() { var ball = make(chan string) kickBall := func(playerName string) { for { fmt.Print(<-ball, “传球”, “\n”) time.Sleep(1 * time.Second) ball <- playerName } } go kickBall(“张三”) go kickBall(“李四”) go kickBall(“王五”) go kickBall(“赵六”) ball <- “裁判” var c chan bool <-c }

分界线


第二份代码如下

package main

func main() { var c chan bool <-c }


Golang Go语言中两份代码对比,为什么第一份代码不会panic,第二份代码会panic

更多关于Golang Go语言中两份代码对比,为什么第一份代码不会panic,第二份代码会panic的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

22 回复

第一份代码也是有 panic 的潜力的,建议读 https://tour.go-zh.org/concurrency/2

更多关于Golang Go语言中两份代码对比,为什么第一份代码不会panic,第二份代码会panic的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


所有线程都阻塞就 panic 了

第二个没有运行中的协程,编译器直接判断死锁了,随便加一个就可以了

说错 不是编译器判断 是运行中判断的

能写出第二个代码,有一个基本的原则你没有弄明白。即 channel 的用途:在不同的协程之间进行消耗的传递,而第二份代码,即对 channel 没有初始化,也没有额外的协程存在。

#1 emmm 抱歉看错了

chan 不是要 make 来创建吗,var **也行?

第二个没懂先看基础文档吧。。。。。

var 是声明

所有 goroutine 都睡了就会 panic


明白了,panic 会发生在所有的协程都被阻塞的情况下。把第一个程序简化为这样之后,也不会 panic 。因为 go 启动的一个协程在不断的运行,所以不会 panic

package main

func main() {
go func() {
for {
}
}()
var c chan bool
<-c
}


明白了,多谢多谢

我看 op 的贴,把第二段代码加了个放东西的协程,感觉就不会出错了,然而还是报错,OP 知道啥原因吗?
package main

import (
“fmt”
)

func main() {
var c chan bool
go func() {
c <- true
}()
fmt.Println(<-c)
}

对 nil chan 做 send 或 recv 都会导致永远阻塞


你把代码改成这样,就不会 panic 了

原因就是 channel 没有初始化,只是做了 var 的声明

package main

import (
“fmt”
)

func main() {
//var c chan bool
c := make(chan bool)
go func() {
c <- true
}()
fmt.Println(<-c)
}

go 允许对一个 nil chan 进行读操作,这会导致阻塞。第二个例子会监测到死锁 panic 的原因是程序中没有其他 goroutine 正在运行。值得说明的是,这里不仅仅是要求有其他 goroutine 在运行,而且也不能全部同时阻塞,此时 go 运行时会监测到程序无法解除阻塞状态,从而再次导致死锁 panic 。

下面的代码说明了 [其他 goroutine 不能全部同时阻塞的情况] :
<br> go func() {<br> var cc = make(chan bool)<br> &lt;-cc<br> }()<br> var c = make(chan bool)<br> &lt;-c<br>

最后:通过第二段代码(无论 chan 是否通过 make 创建)来阻塞主程序不是合理的实践,原因上面说了,当程序中只剩下一个 goroutine (主)在运行时,这种代码会死锁 panic 并退出。

把 “var c chan bool” 改成 “var c = make(chan bool)”就可以了,未初始化的 chan 变量并没有分配任何内存空间,因此无法进行读写操作

import 一个"net"也不会 panic🤣🤣🤣

唉,问了一个问题,还得到了一份错误的答案!好好看看 channel 和 groutine 的文档吧,每一次阅读和编写 demo ,相信你都能有不同的提升。

求明说,或者给一个去验证的方向

在Golang中,代码是否会导致panic通常取决于多个因素,包括变量使用前的初始化状态、对空指针或nil值的解引用、数组越界访问等。针对你提到的两份代码对比,以下是一些可能的原因分析:

  1. 变量初始化:第一份代码可能在使用变量前进行了适当的初始化,确保变量在使用时不是nil或未定义状态。而第二份代码可能遗漏了某些变量的初始化,导致在运行时尝试访问未初始化的变量,从而引发panic。

  2. 空指针解引用:在第二份代码中,可能存在对nil指针的解引用操作,如调用nil对象的方法或访问nil指针指向的内存。而在第一份代码中,这种操作可能被避免了,或者相关的指针在使用前被正确赋值。

  3. 数组/切片越界:如果第二份代码中涉及到数组或切片的访问,可能存在索引越界的情况,这在Golang中会导致运行时panic。而第一份代码在处理数组或切片时,可能确保了索引的有效性。

  4. 并发问题:在涉及并发编程时,如果第二份代码中的goroutine或channel使用不当(如向已关闭的channel发送数据),也可能导致panic。第一份代码则可能正确地管理了并发资源。

为了更准确地诊断问题,建议检查两份代码的具体实现,特别是上述提到的潜在问题点。如果可能,使用Go的静态分析工具(如golint、go vet)或运行时调试器(如Delve)来帮助识别潜在问题。

回到顶部