Go语言第十一课 并发(二)Channel

先明确一个关于内存共享的基本概念:

进程:既不共享堆内存,也不共享栈内存

线程:共享堆内存,不共享栈内存

协程:共享堆内存,也共享栈内存

协程间通信——channel

channel类型

每一个channel都是一个特殊的类型,例如可传递int类型数据的channel是chan int类型

package main

import (
	"fmt"
	"reflect"
)

func main() {
	channel_test := make(chan int)
	fmt.Println(reflect.TypeOf(channel_test))
}

结果

chan int

注意:通过make创建的chan int类型实际上是指针类型,其值channel_test实际上是根指针。若将channel_test赋值给其他chan int的变量将发生地址值的拷贝,而不是实际指向的数据的拷贝。chan int类型的零值是nil。

只有相同类型的channel值之间才能比较(使用==)。如果两个channel值指向同一个地址则==成立。任何类型的channel值都可以与nil比较。

发送和接收

发送和接受是channel的两个基本操作。

package main

import (
	"bufio"
	"os"
	"fmt"
	"strings"
)

func main() {
	channel_test := make(chan string)
	go func() {
		for {
			x := <-channel_test
			fmt.Print("receive:" + x)
		}
	}()

	for {
		inputReader := bufio.NewReader(os.Stdin)
		str, err := inputReader.ReadString('\n')
		if err == nil {
			channel_test <- str
			if strings.Compare(str, "stop\n") == 0 {
				break
			}
		}
	}

}

结果

aaa
receive:aaa
bbb
receive:bbb
ccc
receive:ccc
stop


Process finished with exit code 0

这是一个从主协程向另一个协程不断发送string类型数据的例子,很明显这是一个同步阻塞的例子。

另外,消费channel数据时,也可以不指定消费变量,例如上面的例子中

x := <-channel_test

可改为

<-channel_test

这样的话,协程即放弃channel的数据并继续向后运行。

close内置函数

还可以使用close内置函数关闭一个channel。

向已关闭的channel发送数据均会导致panic异常。

从已关闭的channel内读取数据,如果channel已有数据,此数据将被读出;如果没有数据将得到默认零值。

只收/只发channel

chan string定义的是收发channel。还可以定义只收/只发channel。例如上面的例子可改为

package main

import (
	"bufio"
	"os"
	"fmt"
	"strings"
)

func main() {
	channel_test := make(chan string)

	go output(channel_test)

	for {
		inputReader := bufio.NewReader(os.Stdin)
		str, err := inputReader.ReadString('\n')
		if err == nil {
			input(channel_test, str)
			if strings.Compare(str, "stop\n") == 0 {
				break
			}
		}
	}

}

//send only
func input(ch chan<- string, msg string) {
	ch <- msg
}

//receive only
func output(ch <-chan string) {
	for {
		x := <-ch
		fmt.Print("receive:" + x)
	}
}

没有任何语法支持将单向channel拓展成双向的channel或者反向。

猜你喜欢

转载自blog.csdn.net/yongyu_it/article/details/80884725