英文:
Can I use make(chan someStruct) in go?
问题
例如:
type name struct {
name string
age int
}
func main() {
c := make(chan name)
c <- name{"sfsaf", 1}
a, b := <- c
close(c)
}
结果:
致命错误:所有的goroutine都处于休眠状态 - 死锁!
我想通过通道传递值。我应该怎么做?
英文:
for example:
type name struct {
name string
age int
}
func main() {
c := make(chan name)
c <- name{"sfsaf", 1}
a, b := <- c
close(c)
}
The result:
> fatal error: all goroutines are asleep - deadlock!
I want to pass values through channel. What should I do?
答案1
得分: 21
是的,你可以传递结构体。但这不是你的问题所在。
你在没有接收方准备好接收的情况下向通道发送了一个值。这就是导致死锁的原因。
通道期望“接收方”阻塞,等待“发送方”。这是通过使用 Goroutine 实现的。
因此,将发送方包装在一个 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!).")
}
在 playground 上查看:https://play.golang.org/p/uaSuCaB4Ms
这段代码之所以有效,是因为发送方的 Goroutine 还没有执行。直到当前正在执行的 Goroutine 被阻塞。
我们在 for n := range c
循环中被阻塞,等待接收值。(使用 for 循环迭代通道值是一种常见的模式,它会阻塞等待值的到来)。
因此,现在我们被阻塞在 for
循环中等待接收值,内联 Goroutine 将会执行,将我们的值发送到通道上。
此外,我们遵循安全的做法,在完成后清理并关闭通道,向 for
循环或 select
语句发出不再发送值的信号。发送方总是关闭通道,接收方不关闭。这是 for
range 循环用于退出循环并继续执行其余代码的模式。
另外,你做得很好,传递了结构体的值而不是指针。
如果你传递了指针,你将不得不在对象周围实现一些互斥锁,以防止读写冲突。
在通道和 Goroutine 之间传递值而不是指针,并获得好处。
英文:
Yes you can pass structs. But that's not the problem in your OP.
You sent a value on a channel, when there was no receiver ready to receive. That is what caused your deadlock.
Channels expect the receiver
to be blocking, waiting for the sender
. This is done with Goroutines.
Therefore, wrap your sender in a goroutine, which will not execute right away.
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!).")
}
See it in the playground: https://play.golang.org/p/uaSuCaB4Ms
This works because the sender's goroutine is not executing yet. Not until the current goroutine executing gets blocked.
And we get blocked on the for n := range c
loop. This is the receiver, sitting and waiting for values. (It is a common pattern to use the for loop to iterate over channel values as it will sit and block, waiting for values).
So now that we are blocked waiting to receive values in the for
loop, the inline gorouting will now execute, to send our value on the channel.
In addition, we follow safe practices and tidy up after ourselves and close(c)
the channel, signalling the for
loop or select
statement that there will be no more values sent. The sender always closes, never the receiver. This is the pattern the for
range loop uses to exit the for loop, and continue executing the rest of your code.
As a side note, you did well by passing the value of the struct - not a pointer.
If you passed a pointer, you'd have to implement some mutex lock around the object to prevent a R/W panic.
Do not communicate by sharing memory; instead, share memory by communicating.
Stick to passing values, not pointers, around your channels and goroutines and reap the benefits.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论