I'm working on understanding Go's channels. I think I understand a basic bidirectional chan
but I'm falling short at understanding <-chan
and chan<-
.
I expected them to be useful for communicating one way to a thread but I'm having issues with the thread actually reading and receiving the value.
package main
import (
"fmt"
"time"
)
func Thread(c chan<- int) {
for {
num := <-c
fmt.Println("Thread : ", num)
time.Sleep(time.Second)
}
}
func main() {
c := make(chan<- int, 3)
go Thread(c)
for i := 1; i <= 10; i++ {
c <- i
}
for len(c) > 0 {
time.Sleep(100)
}
}
I've tried using <-chan
instead of chan<-
in the make()
but the same kind of thing happens:
C:\>go run chan.go
# command-line-arguments
.\chan.go:10: invalid operation: <-c (receive from send-only type chan<- int)
If I can't read from the channel, why bother writing to it? With that thought in mind, I figure I must be doing something wrong. I had the expectation that a send only chan
would mean that one thread can only send while the other thread can only receive. This does not seem to be the case.
If I remove the <-
entirely, it works, but that would make it bidirectional allowing the go routine to respond (even though it never does) and I'm looking to avoid that. It seems like I can banish numbers to a chan
that I'll never be able to read from, or that I could read from a chan
that's impossible to write to.
What I'm hoping to do is send integers from the main thread to the go routine for it to print using a one way channel. What am I doing wrong?
This is with go 1.3.3 on Windows if it matters. Updating to 1.4 didn't help. I might want to mention this is all x64 as well.
The Go Programming Language Specification
Channel types
A channel provides a mechanism for concurrently executing functions to communicate by sending and receiving values of a specified element type. The value of an uninitialized channel is nil.
ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
The optional <- operator specifies the channel direction, send or receive. If no direction is given, the channel is bidirectional. A channel may be constrained only to send or only to receive by conversion or assignment.
You can be explicit about channel direction by conversion or assignment. For example, by conversion,
package main
import (
"fmt"
"time"
)
func Thread(r <-chan int) {
for {
num := <-r
fmt.Println("Thread : ", num)
time.Sleep(time.Second)
}
}
func main() {
c := make(chan int, 3)
s, r := (chan<- int)(c), (<-chan int)(c)
go Thread(r)
for i := 1; i <= 10; i++ {
s <- i
}
for len(c) > 0 {
time.Sleep(100)
}
}
Output:
Thread : 1 Thread : 2 Thread : 3 . . .
Or, equivalently, by assignment,
package main
import (
"fmt"
"time"
)
func Thread(r <-chan int) {
for {
num := <-r
fmt.Println("Thread : ", num)
time.Sleep(time.Second)
}
}
func main() {
c := make(chan int, 3)
var s chan<- int = c
var r <-chan int = c
go Thread(r)
for i := 1; i <= 10; i++ {
s <- i
}
for len(c) > 0 {
time.Sleep(100)
}
}
Go allows to create send- or receive-only channels like c := make(<-chan int)
, however, I haven't came across a use case. There is a discussion here in github.
About the error in the code;
func Thread(c chan<- int) {
for {
num := <-c
fmt.Println("Thread : ", num)
time.Sleep(time.Second)
}
}
Function parameter c
can only be sent to. Attempting to receive from c will result in a compiler error but the line num := <-c
tries to receive.
At the end, fixed version;
package main
import (
"fmt"
"time"
)
func Thread(c <-chan int) {
for {
num := <-c
fmt.Println("Thread : ", num)
time.Sleep(time.Second)
}
}
func main() {
c := make(chan int, 3)
go Thread(c)
for i := 1; i <= 10; i++ {
c <- i
}
for len(c) > 0 {
time.Sleep(100)
}
}
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