我可以在 go 中使用 make(chan someStruct) 吗?

Posted

技术标签:

【中文标题】我可以在 go 中使用 make(chan someStruct) 吗?【英文标题】:Can I use make(chan someStruct) in go? 【发布时间】:2017-11-12 19:31:20 【问题描述】:

例如:

type name struct 
    name string
    age int


func main() 
      c := make(chan name)

      c <- name"sfsaf", 1
      a, b := <- c

      close(c)

结果:

致命错误:所有 goroutine 都处于休眠状态 - 死锁!

我想通过通道传递值。我该怎么办?

【问题讨论】:

Channel 用于并发函数之间的通信。在您的示例中,写入和读取操作不是并发的,从而导致死锁。在 goroutine 内执行读取或写入,例如go func() c &lt;- name"sfsaf", 1 (). ***.com/questions/36505012/… 的可能重复项。 @CeriseLimón 这不是一个重复的问题。那个没有显示如何使用make(chan somestruct) @putu 谢谢,我会试试的。你怎么看make(chan non-empty-struct) 没有理由close 频道,除非您发出信号表明您的接收将不再有值(例如使用for range 循环)。请参阅下面发布的我的答案,更新了有关如何使用频道的更多详细信息。 【参考方案1】:

是的,您可以传递结构。但这不是您的 OP 中的问题。

当没有接收器准备好接收时,您在通道上发送了一个值。这就是导致您陷入僵局的原因。

频道期望 receiver 被阻塞,等待 sender。这是通过 Goroutines 完成的。

因此,将您的发件人包装在一个不会立即执行的 goroutine 中。

package main

import (
    "fmt"
)

type name struct 
    name string
    age  int


func main() 
    c := make(chan name)

    go func() 
        c <- name"sfsaf", 1
        close(c)
    ()

    for n := range c 
        fmt.Println(n)
    

    fmt.Println("channel was closed (all done!).")

在操场上看到它:https://play.golang.org/p/uaSuCaB4Ms

这是可行的,因为发送者的 goroutine 还没有执行。直到当前执行的 goroutine 被阻塞。

我们在for n := range c 循环中被阻止。这是接收者,坐着等待值。 (使用 for 循环迭代通道值是一种常见的模式,因为它会坐下来阻塞,等待值)。

所以现在我们被阻止等待在 for 循环中接收值,内联 gorouting 现在将执行,以在通道上发送我们的值。

此外,我们遵循安全惯例并在自己和close(c) 频道之后进行整理,向for 循环或select 声明发出信号,表示将不再发送任何值。 发送者总是关闭,接收者永远不会。这是for range 循环用于退出 for 循环并继续执行其余代码的模式。


顺便说一句,您通过传递结构的值而不是指针做得很好。

如果你传递了一个指针,你必须在对象周围实现一些互斥锁来防止 R/W 恐慌。

Do not communicate by sharing memory; instead, share memory by communicating.

坚持在通道和 goroutine 周围传递值,而不是指针,并从中获益。

【讨论】:

感谢您的回答。我想知道如何获取结构的元素。在这个例子中,我想得到 我知道了,应该使用 ( 你怎么能保证上面的代码总是有效的?换句话说,for循环上面的goroutine在命中for循环后会被执行的保证是什么? @user1870400 这是语言的设计。由于 Golang 在设计上是一种程序性(例如命令式)语言,因此它按顺序执行操作。在 Golang 规范中(找不到链接 atm),go func() 指令被推迟执行,直到当前 goroutine 被阻塞 - 这发生在上面列出的代码中的 for n := range c 操作上。为了缓解混乱,每个操作,包括main(),都在一个goroutine中执行。您的整个应用程序在单个 goroutine 中运行,直到您调用 go func() - 现在您将拥有两个 goroutine。

以上是关于我可以在 go 中使用 make(chan someStruct) 吗?的主要内容,如果未能解决你的问题,请参考以下文章

Go管道注意细节

go chan 入门代码

Go 只读/只写channel

go channel 管道

Go语言中new与make的区别

go语言的new和make