[Go] Channel 通道

213 阅读2分钟

单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义。

虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,这种做法势必造成性能问题。

Go语言的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信

如果说goroutine是Go程序并发的执行体,channel就是它们之间的连接。channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制。

Go 语言中的通道(channel)是一种特殊的类型。通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。

package main

import (
   "fmt"
   "sync"
)
var wg sync.WaitGroup

func main() {
   wg.Add(2)
   var chan1,chan2 chan int
   chan1 = make(chan int,100)
   chan2 = make(chan int,100)
   // 协程调用方法
   go f1(chan1)
   go f2(chan1,chan2)
   wg.Wait()
   // 打印通道chan2的数据内容
   for ret := range  chan2{
      fmt.Println(ret)
   }
}

// 通道c1写入数据
func f1(c1 chan int) {
   defer wg.Done()
   defer close(c1)
   for i:=0;i<100;i++ {
      c1 <- i
   }
}

// 从通道c1取出值,然后计算结果写入到通道c2
func f2(c1,c2 chan int)  {
   defer wg.Done()
   defer close(c2)
   for {
      x,ok := <- c1
      if !ok {
         break
      }
      c2 <- x*x
   }
}

现在呢,我们要对于以上的方法进行一个改写,比如f1的方法现在既可以写通道,也可以读通道,所以我们要把它处理成单向通道,让它只能读,或者只能写:

package main

import "fmt"

// 单向通道演示
func main() {
   var c chan int
   c = make(chan int, 10)
   fc1(c)
   fc2(c)
   close(c)
}

// 该方法中只能往c1写入
func fc1(c1 chan<- int) {
   c1 <- 666
}

// 该方法中只能从c1取出数据
func fc2(c1 <-chan int) {
   x := <- c1
   fmt.Println(x)
}