When passing a channel to a function, I know you can specify the direction that channel may use the channel for; for example,
func MyFunc(ch chan<- string) {
ch <- "Hello"
}
"ch" can only be used by MyFunc to send strings to a receiver elsewhere and MyFunc cannot listen for messages from ch.
To simplify creating a dynamic number of channels to some number of goroutines, I created a struct containing channels.
type ChanStruct struct {
chMessages chan string
}
Then I instantiate a structs:
var slcChanStruct []ChanStruct
for a:= 0; a <=2; a++ {
var tmpChanStruct ChanStruct
tmpChanStruct.chMessages = make(chan string)
slcChanStruct = append(slcChanStruct, tmpChanStruct)
}
Now I have 3 structs I can individually read/write with a channel by ranging over a slice of structs. But when I send them off to goroutines:
for a:=0; a <=2; a++{
go SomeFunc(slcChanStruct[a])
}
...is there a way to add a bit of safety by specifying that the goroutines can only, for example, send using the ChanStruct.ch channel?
NOTE the reason I was doing this is that if I don't know how many channels I'll need for a parallel set of processes (the number of processes are passed as a command line argument) using a struct with channels means I can create a slice that can be passed to any number of goroutines and directly access them individually by ranging over them; before, I had to create a set number of channels if I wanted to individually read from a number of goroutines. I'd like to add some safety to this by specifying that processes can only use a channel a certain way, like I could when using individual channels (individual channels mean I can do something like telling a particular goroutine to quit without other goroutines intercepting it). Is there a more idiomatic way to do this if I can't add directionality to functions using the channel in a struct?
In Golang, or Go, channels are a means through which different goroutines communicate. Think of them as pipes through which you can connect with different concurrent goroutines. The communication is bidirectional by default, meaning that you can send and receive values from the same channel.
In the channel, the send and receive operation block until another side is not ready by default. It allows goroutine to synchronize with each other without explicit locks or condition variables. Send operation: The send operation is used to send data from one goroutine to another goroutine with the help of a channel.
This means channels can start out bidirectional, but magically become directional simply by assigning a regular channel to a variable of a constrained type. This is very useful for creating receive-only channels that no one can close but you.
Buffered channels in Go are always FIFO. The specification clearly says: Channels act as first-in-first-out queues. If the values coming out of the channel are not FIFO, then this is a bug in the channel implementation.
On top of @Adrian's suggestions, if you have to ensure one way communication on a channel, you can always use an anonymous function:
for a:=0; a <=2; a++{
go func f(ch <-string) {
SomeFunc(ch)
}(slcChanStruct[a].chMessages)
}
Note that you'll have to pass the channel to SomeFunc
instead of the struct.
If you still want to perform both way communication on your channel, you can re assign the channel to a one directional type:
type ChanStruct struct {
chMessages chan string
}
type ChanStructRecv struct {
chMessages <-chan string
}
// Update SomeFunc type:
func SomeFunc(s ChanStructRecv) {
// ...
}
Finally, the loop can be modified similarly:
for a:=0; a <=2; a++{
go func f(s ChanStruct) {
var sr ChanStructRecv
sr.chMessages = s.chMessages
SomeFunc(sr)
}(slcChanStruct[a])
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With