如何使用< -chan和chan< - 进行单向通信?

时间:2014-12-24 20:55:17

标签: go channel

我正在努力了解Go的频道。我想我理解一个基本的双向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)
    }
}

我尝试在<-chan中使用chan<-代替make(),但同样的事情发生了:

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上使用1.3.3。更新到1.4没有帮助。我可能想提一下这也是x64。

3 个答案:

答案 0 :(得分:4)

  

The Go Programming Language Specification

     

Channel types

     

通道提供了一种同时执行函数的机制   通过发送和接收指定元素的值进行通信   类型。未初始化频道的值为零。

ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
     

可选&lt; - 运算符指定通道方向,发送或   接收。如果没有给出方向,则通道是双向的。一个   通道可能仅限于发送或仅接收   转换或转让。

您可以通过转换或分配明确说明频道指示。例如,通过转换,

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)
    }
}

答案 1 :(得分:1)

Go允许创建像c := make(<-chan int)这样的发送或接收频道,但是,我还没有遇到过用例。 github中有一个讨论here

关于代码中的错误;

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)
    }
}

答案 2 :(得分:0)

您的Thread功能正在传递仅发送频道,而不是仅接收频道。但是,您不需要make()它只接收,您可以将双向通道传递给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)
    }
}

您可以通过添加行

来验证这一点
c <- 3

Thread函数中,抛出错误prog.go:11: invalid operation: c <- 3 (send to receive-only type <-chan int)

请参阅https://play.golang.org/p/5KNPNLqA_k