Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang channel in a struct: Can it be directional when passed to a function?

Tags:

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?

like image 739
Bart Silverstrim Avatar asked Jun 02 '17 13:06

Bart Silverstrim


People also ask

Is Go channel bidirectional?

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.

How does channels work in Golang?

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.

What are directional channels in Go language?

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.

Are Go channels FIFO?

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.


1 Answers

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])
}
like image 149
abhink Avatar answered Oct 11 '22 12:10

abhink