英文:
How to use <-chan and chan<- for one directional communication?
问题
我正在努力理解Go语言中的通道(channels)。我认为我理解了基本的双向chan
,但是我对<-chan
和chan<-
的理解还不够。
我原以为它们可以用于向线程单向通信,但是我在实际读取和接收值时遇到了问题。
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)
}
}
我尝试在make()
中使用<-chan
而不是chan<-
,但是出现了相同的问题:
C:\>go run chan.go
# command-line-arguments
.\chan.go:10: invalid operation: <-c (receive from send-only type chan<- int)
如果我不能从通道中读取,为什么还要写入呢?考虑到这一点,我觉得我一定做错了什么。我原以为只能发送的chan
意味着一个线程只能发送,而另一个线程只能接收。但事实似乎并非如此。
如果我完全删除<-
,它可以工作,但这将使其变为双向通道,允许go例程做出响应(尽管它从未这样做),而我希望避免这种情况。似乎我可以将数字发送到一个我永远无法从中读取的chan
,或者我可以从一个无法写入的chan
中读取。
我希望能够通过单向通道将整数从主线程发送到go例程,以便它打印出来。我做错了什么?
这是在Windows上使用Go 1.3.3进行的,如果有关系的话,我可能还想提一下这都是x64的。
英文:
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.
答案1
得分: 7
《Go编程语言规范》
通道类型
通道提供了一种机制,用于并发执行的函数通过发送和接收指定元素类型的值来进行通信。未初始化的通道的值为nil。
ChannelType = ("chan" | "chan" "<-" | "<-" "chan") ElementType.
可选的"<-"运算符指定通道的方向,发送或接收。如果没有给出方向,则通道是双向的。通过转换或赋值,可以明确通道的方向。
例如,通过转换:
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)
}
}
输出:
Thread: 1
Thread: 2
Thread: 3
...
或者,等效地,通过赋值:
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)
}
}
英文:
> 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:
<pre>
Thread : 1
Thread : 2
Thread : 3
. . .
</pre>
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)
}
}
答案2
得分: 1
Go允许创建只发送或只接收的通道,例如c := make(<-chan int)
,然而,我还没有遇到过使用的情况。在GitHub上有一个讨论这里。
关于代码中的错误:
func Thread(c chan<- int) {
for {
num := <-c
fmt.Println("Thread: ", num)
time.Sleep(time.Second)
}
}
函数参数c
只能发送数据。尝试从c
接收数据将导致编译错误,但是num := <-c
这一行尝试接收数据。
修复后的版本如下:
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)
}
}
英文:
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)
}
}
答案3
得分: 0
你的Thread
函数传递的是一个只发送的通道,而不是只接收的通道。但是你不需要将它的类型设置为只接收,你可以将一个双向通道作为只接收的通道传递给goroutine。
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)
}
}
你可以通过在Thread
函数中添加以下代码来验证:
c <- 3
这将抛出错误prog.go:11: invalid operation: c <- 3 (send to receive-only type <-chan int)
。
参考链接:https://play.golang.org/p/5KNPNLqA_k
英文:
Your Thread
function is passing a send-only channel, instead of a receive-only channel. But you don't need to make()
it receive-only, you can pass a bidirectional channel to a goroutine as receive-only.
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)
}
}
You can verify this by adding the line
c <- 3
in your Thread
function, throwing the error prog.go:11: invalid operation: c <- 3 (send to receive-only type <-chan int)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论