先明确一个关于内存共享的基本概念:
进程:既不共享堆内存,也不共享栈内存
线程:共享堆内存,不共享栈内存
协程:共享堆内存,也共享栈内存
协程间通信——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或者反向。