Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Go程序中使用select时应出现死锁_Go_Select_Deadlock - Fatal编程技术网

在Go程序中使用select时应出现死锁

在Go程序中使用select时应出现死锁,go,select,deadlock,Go,Select,Deadlock,以下Go程序(扩展自,完整源代码)使用无缓冲通道: func service1(c chan string) { time.Sleep(3 * time.Second) fmt.Println("Ready to send on chan 1") c <- "Hello from service 1" fmt.Println("Sent on chan 1") } func service2(c

以下Go程序(扩展自,完整源代码)使用无缓冲通道:

func service1(c chan string) {
    time.Sleep(3 * time.Second)
    fmt.Println("Ready to send on chan 1")
    c <- "Hello from service 1"
    fmt.Println("Sent on chan 1")
}

func service2(c chan string) {
    time.Sleep(2 * time.Second)
    fmt.Println("Ready to send on chan 2")
    c <- "Hello from service 2"
    fmt.Println("Sent on chan 2")
}

func service3(c chan string) {
    time.Sleep(3 * time.Second)
    fmt.Println("Ready to receive on chan 3")
    res := <- c
    fmt.Println("Response from service main", res, time.Since(start))
}


func main() {
    fmt.Println("main() started", time.Since(start))

    chan1 := make(chan string)
    chan2 := make(chan string)
    chan3 := make(chan string)

    go service1(chan1)
    go service2(chan2)
    go service3(chan3)

    select {
    case res := <-chan1:
        fmt.Println("Response from service 1", res, time.Since(start))
    case res := <-chan2:
        fmt.Println("Response from service 2", res, time.Since(start))
    case chan3 <- "Hello from main":
        fmt.Println("Sent to service 3")
    }
    
    time.Sleep(5 * time.Second)
    
    fmt.Println("main() stopped", time.Since(start))
}
我本以为
service1
service3
会导致死锁,因为
main
中的
select
语句会选择第二种情况。但是,这两个goroutine既不阻塞也不完全执行(因为最终打印不会反映在输出中)


我对的理解是,尽管对操作数进行了计算,但不应执行通道1上的接收和通道3上的发送。如果错误,请纠正,并帮助阐明这种行为。谢谢大家!

select语句是一条阻塞语句,将等待至少一条语句成功求值。因此,在上面的示例中,由于
service2
的睡眠时间最少
(2秒)
,因此首先执行它,然后退出select语句

现在您正在等待5秒钟。但这不会执行
service1
service3
,因为
select
语句已经退出,并且
service1
service3
没有接收go例程

使用一个简单的
for
循环,您可以等待所有go例程执行完毕。我已经用这个更改更新了完整的源代码。即使使用
for
循环,也不会出现任何死锁,因为select语句确保在给定时间只运行一条语句。如果两条语句准备执行,则随机选择其中一条

package main

import (
    "fmt"
    "time"
)

var start time.Time

func init() {
    start = time.Now()
}

func service1(c chan string) {
    time.Sleep(3 * time.Second)
    fmt.Println("Ready to send on chan 1")
    c <- "Hello from service 1"
    fmt.Println("Sent on chan 1")
}

func service2(c chan string) {
    time.Sleep(2 * time.Second)
    fmt.Println("Ready to send on chan 2")
    c <- "Hello from service 2"
    fmt.Println("Sent on chan 2")
}

func service3(c chan string) {
    time.Sleep(3 * time.Second)
    fmt.Println("Ready to receive on chan 3")
    res := <-c
    fmt.Println("Response from service main", res, time.Since(start))
}

func main() {
    fmt.Println("main() started", time.Since(start))

    chan1 := make(chan string)
    chan2 := make(chan string)
    chan3 := make(chan string)

    go service1(chan1)
    go service2(chan2)
    go service3(chan3)
    for i := 0; i < 3; i++ {
        select {
        case res := <-chan1:
            fmt.Println("Response from service 1", res, time.Since(start))
        case res := <-chan2:
            fmt.Println("Response from service 2", res, time.Since(start))
        case chan3 <- "Hello from main":
            fmt.Println("Sent to service 3")
        }
    }

    fmt.Println("main() stopped", time.Since(start))
}
主程序包
进口(
“fmt”
“时间”
)
变量开始时间。时间
func init(){
开始=时间。现在()
}
func service1(c chan字符串){
时间。睡眠(3*时间。秒)
fmt.Println(“准备发送到chan 1”)

c main只是在select语句之后退出,当main退出程序时,不管发生什么情况。此外,对于死锁,所有的goroutine都必须被阻止,但主goroutine不是。啊,我明白了!我错过了这个重要信息,即死锁是由所有被阻止的goroutine定义的。@andre_c是否存在不涉及所有goroutine的死锁成员?“在并行计算中,死锁是指组中的每个成员等待另一个成员(包括其自身)采取行动的状态…”go运行时不够聪明,无法确定某个特定的goroutine是否最终会被唤醒,事实上,这个问题在总体上可能无法解决,因为它听起来与停止问题非常相似。
package main

import (
    "fmt"
    "time"
)

var start time.Time

func init() {
    start = time.Now()
}

func service1(c chan string) {
    time.Sleep(3 * time.Second)
    fmt.Println("Ready to send on chan 1")
    c <- "Hello from service 1"
    fmt.Println("Sent on chan 1")
}

func service2(c chan string) {
    time.Sleep(2 * time.Second)
    fmt.Println("Ready to send on chan 2")
    c <- "Hello from service 2"
    fmt.Println("Sent on chan 2")
}

func service3(c chan string) {
    time.Sleep(3 * time.Second)
    fmt.Println("Ready to receive on chan 3")
    res := <-c
    fmt.Println("Response from service main", res, time.Since(start))
}

func main() {
    fmt.Println("main() started", time.Since(start))

    chan1 := make(chan string)
    chan2 := make(chan string)
    chan3 := make(chan string)

    go service1(chan1)
    go service2(chan2)
    go service3(chan3)
    for i := 0; i < 3; i++ {
        select {
        case res := <-chan1:
            fmt.Println("Response from service 1", res, time.Since(start))
        case res := <-chan2:
            fmt.Println("Response from service 2", res, time.Since(start))
        case chan3 <- "Hello from main":
            fmt.Println("Sent to service 3")
        }
    }

    fmt.Println("main() stopped", time.Since(start))
}