为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我有一个死锁,即使它包含一个无限循环?

为什么我有一个死锁,即使它包含一个无限循环?

Go
牛魔王的故事 2023-05-15 15:11:46
我开始和 Go 混在一起,我对 go routines 很着迷。我现在写了一个简单的测试,看看我是否可以在连续打印变量的同时更改它的值。我现在有以下代码:package mainimport (    "fmt"    "time")func change(c chan float64) float64 {    time.Sleep(2 * time.Second)    return 2.5}func main() {    s := 1.1    c := make(chan float64)    go change(c)    s = <-c    for {        fmt.Println(s)        time.Sleep(100 * time.Millisecond)    }    }不幸的是它以错误结束:fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan receive]:main.main()        /home/kramer65/repos/go/src/messing_around/main.go:19 +0x7dexit status 2我四处搜索,发现当 main 函数结束而 goroutines 还没有结束时,就会发生这种死锁。但是由于我有一个无限循环,我不知道我的代码还有什么问题。这段代码有什么问题,我如何在不断打印变量的同时更改它的值?
查看完整描述

1 回答

?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

看起来你可能对频道和套路有误解。


该行:


go change(c)

似乎表明该函数change将写入c. 然而,它最终只是在一段时间后返回一个值。


此值 ( 2.5) 不会在任何地方收到。此外,c不会被写入任何地方。我怀疑您打算将其2.5写入频道c。其语法如下:


c<-2.5

因此,如果您将change函数更改为:


func change(c chan float64) {

    time.Sleep(2 * time.Second)

    c <- 2.5

}

你不应该再看到死锁了。请注意,我不再返回 afloat64了。


我做了一个游乐场来确保这一点:https ://play.golang.org/p/SgLiUmPpcAZ


更新评论


将1.1始终被通道的值覆盖。但是,如果您想打印 prints的初始值(如评论中所述),则必须稍微更改流程并使用语句select:


package main


import (

    "fmt"

    "time"

)


func change(c chan float64) {

    time.Sleep(2 * time.Second)

    c <- 2.5

}


func main() {


    s := 1.1


    c := make(chan float64)

    go change(c)


    for {

        select {

        case s = <-c:

        default:

            // c isn't ready yet

        }

        fmt.Println(s)

        time.Sleep(100 * time.Millisecond)

    }

}

现在您有了一个select语句,您也可以将它与 atime.Ticker一起使用:


ticker := time.NewTicker(100 * time.Millisecond)

for {

    select {

    case s = <-c:

    case <-ticker.C:

        fmt.Println(s)

    default:

        // c isn't ready yet

    }

}


查看完整回答
反对 回复 2023-05-15
  • 1 回答
  • 0 关注
  • 103 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信