为什么golang中的频道需要一个常规例程?

时间:2017-05-27 11:44:24

标签: go

我正在加速golang的频道。根据{{​​3}},

  

频道是您可以通过其发送和接收的类型管道   使用通道运算符的值< - 。

我明白了。我理解如何使用go例程的例子。我尝试了一个非常简单的例子。它导致程序陷入僵局。忽略这个程序的无意义,请你告诉我为什么这个问题陷入僵局?

package main
import  "fmt"
func main() {
    c := make(chan int)
    c <- 17
    fmt.Println(<- c)
}

引用文档补充说明

  

默认情况下,发送和接收阻止,直到另一方准备好。

好的,在上面的示例中,遇到c <- 17时,发件人(主例程) 准备发送。所以不应该执行。随后Println应该能够消耗频道。

如果将c <- 17替换为

,我意识到一切正常
go func() { c <- 17 } ()

只是想了解为什么这是必要的。

2 个答案:

答案 0 :(得分:5)

  

默认情况下,发送和接收阻止,直到另一方准备好。

确切地说:由于没有等待接收的常规例程,发送被阻止,并且您的程序陷入僵局。发送操作不会被跳过,因为没有人等待接收。

如果你想进行非阻塞发送,你可以在带有默认情况的select语句中使用send运算符:

select {
case c <- 17:
default:
}

答案 1 :(得分:3)

  

The Go Programming Language Specification

     

Channel types

     

通道提供了一种同时执行函数的机制   通过发送和接收指定元素的值进行通信   类型。

     

可以使用内置的新的初始化通道值   function make,它采用通道类型和可选容量   作为参数:

make(chan int, 100)
     

容量(以元素数量)设置缓冲区的大小   这个频道。如果容量为零或不存在,则通道为   无缓冲和通信只有当发送者和发送者都成功时才会成功   接收器准备好了。否则,通道被缓冲   如果缓冲区未满,则通信成功而不会阻塞   (发送)或不空(接收)。零通道永远不会准备好   通信。

你问:为什么golang中的频道需要一个常规程序?

Go通道不需要goroutine。成功发送仅需要准备好的接收器或未满的缓冲器。例如,使用缓冲通道

package main

import "fmt"

func main() {
    c := make(chan int, 1)
    c <- 17
    fmt.Println(<-c)
}

输出:

17

您的示例失败,因为它尝试发送没有准备接收器的无缓冲通道。

package main

import "fmt"

func main() {
    c := make(chan int)
    c <- 17
    fmt.Println(<-c)
}

输出:

fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
    /home/peter/gopath/src/sri.go:7 +0x59

@Tim Cooper's proposed solution有同样的错误。

package main

import "fmt"

func main() {
    c := make(chan int)
    select {
    case c <- 17:
    default:
    }
    fmt.Println(<-c)
}

输出:

fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
    /home/peter/gopath/src/tim.go:11 +0x8a