How to use <-chan and chan<- for one directional communication?

huangapple go评论76阅读模式
英文:

How to use <-chan and chan<- for one directional communication?

问题

我正在努力理解Go语言中的通道(channels)。我认为我理解了基本的双向chan,但是我对<-chanchan<-的理解还不够。

我原以为它们可以用于向线程单向通信,但是我在实际读取和接收值时遇到了问题。

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 &lt;-chan and chan&lt;-.

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 (
	&quot;fmt&quot;
	&quot;time&quot;
)

func Thread(c chan&lt;- int) {
	for {
		num := &lt;-c
		fmt.Println(&quot;Thread : &quot;, num)
		time.Sleep(time.Second)
	}
}

func main() {
	c := make(chan&lt;- int, 3)
	go Thread(c)
	for i := 1; i &lt;= 10; i++ {
		c &lt;- i
	}
	for len(c) &gt; 0 {
		time.Sleep(100)
	}
}

I've tried using &lt;-chan instead of chan&lt;- in the make() but the same kind of thing happens:

C:\&gt;go run chan.go
# command-line-arguments
.\chan.go:10: invalid operation: &lt;-c (receive from send-only type chan&lt;- 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 &lt;- 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 (
	&quot;fmt&quot;
	&quot;time&quot;
)

func Thread(r &lt;-chan int) {
	for {
		num := &lt;-r
		fmt.Println(&quot;Thread : &quot;, num)
		time.Sleep(time.Second)
	}
}

func main() {
	c := make(chan int, 3)
	s, r := (chan&lt;- int)(c), (&lt;-chan int)(c)
	go Thread(r)
	for i := 1; i &lt;= 10; i++ {
		s &lt;- i
	}
	for len(c) &gt; 0 {
		time.Sleep(100)
	}
}

Output:

<pre>
Thread : 1
Thread : 2
Thread : 3
. . .
</pre>

Or, equivalently, by assignment,

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func Thread(r &lt;-chan int) {
	for {
		num := &lt;-r
		fmt.Println(&quot;Thread : &quot;, num)
		time.Sleep(time.Second)
	}
}

func main() {
	c := make(chan int, 3)
	var s chan&lt;- int = c
	var r &lt;-chan int = c
	go Thread(r)
	for i := 1; i &lt;= 10; i++ {
		s &lt;- i
	}
	for len(c) &gt; 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(&lt;-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&lt;- int) {
    for {
        num := &lt;-c
        fmt.Println(&quot;Thread : &quot;, 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 := &lt;-c tries to receive.

At the end, fixed version;

package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

func Thread(c &lt;-chan int) {
    for {
        num := &lt;-c
        fmt.Println(&quot;Thread : &quot;, num)
        time.Sleep(time.Second)
    }
}

func main() {
    c := make(chan int, 3)
    go Thread(c)
    for i := 1; i &lt;= 10; i++ {
        c &lt;- i
    }
    for len(c) &gt; 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 (
    &quot;fmt&quot;
    &quot;time&quot;
)

func Thread(c &lt;-chan int) {
    for {
        num := &lt;-c
        fmt.Println(&quot;Thread : &quot;, num)
        time.Sleep(time.Second)
    }
}

func main() {
    c := make(chan int, 3)
    go Thread(c)
    for i := 1; i &lt;= 10; i++ {
        c &lt;- i
    }
    for len(c) &gt; 0 {
        time.Sleep(100)
    }
}

You can verify this by adding the line

c &lt;- 3

in your Thread function, throwing the error prog.go:11: invalid operation: c &lt;- 3 (send to receive-only type &lt;-chan int)

See https://play.golang.org/p/5KNPNLqA_k

huangapple
  • 本文由 发表于 2014年12月25日 04:55:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/27642086.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定