Go SCP 通信顺序进程模型chan通道

4 篇文章 0 订阅

目录

        channer定义

写入 chan

读取 chan

关闭 chan

示例


Go语言实现了两种并发模型,一种是我们熟悉的线程与锁并发模型,他是基于共享内存实现的。另一种是Go语言中倡导使用的SCP 通信顺序进程模型,倡导使用通信手段实现共享内存。

在Go语言中倡导使用channel作为gorotine之间同步和通信的手段。在go语言中的线程是并发机制而不是并行机制。

并发机制和并行机制

并发是不同的代码块交替执行,也就是交替可以做不同的事情。

并行是不同的代码块同时执行,也就是同时可以做不同的事情。

channer定义

        channer 可以理解为队列,遵循队列的先进先出的规则。

// 声明不带缓冲的通道
ch1 := make(chan string)

// 声明带10个缓冲的通道
ch2 := make(chan string, 10)

// 声明只读通道
ch3 := make(<-chan string)

// 声明只写通道
ch4 := make(chan<- string)

//不带缓冲的通道,进和出都会阻塞。
//带缓冲的通道,进一次长度 +1,出一次长度 -1,如果长度等于缓冲长度时,再进就会阻塞。

不带缓冲的通道,进和出都会阻塞。带缓冲的通道,进一次长度 +1,出一次长度 -1,如果长度等于缓冲长度时,再进就会阻塞。

写入 chan

ch1 := make(chan string, 10)

ch1 <- "a"

读取 chan

val, ok := <- ch1
// 或
val := <- ch1

关闭 chan

close(chan)

注意:

  • close 以后不能再写入,写入会出现 panic
  • 重复 close 会出现 panic
  • 只读的 chan 不能 close
  • close 以后还可以读取数据

示例

func main() {
	fmt.Println("main start")
	ch := make(chan string)
	ch <- "a" // 入 chan
	go func() {
		val := <- ch // 出 chan
		fmt.Println(val)
	}()
	fmt.Println("main end")
}

输出:

main start
fatal error: all goroutines are asleep - deadlock!

What ? 这是为啥,刚开始就出师不利呀?

因为,定义的是一个无缓冲的 chan,赋值后就陷入了阻塞。

怎么解决它?

声明一个有缓冲的 chan。

func main() {
	fmt.Println("main start")
	ch := make(chan string, 1)
	ch <- "a" // 入 chan
	go func() {
		val := <- ch // 出 chan
		fmt.Println(val)
	}()
	fmt.Println("main end")
}

输出:

main start
main end

为啥没有输出 a , 和前面一样,主线程执行太快了,加个休眠 1 秒钟,再试试。

func main() {
	fmt.Println("main start")
	ch := make(chan string, 1)
	ch <- "a" // 入 chan
	go func() {
		val := <- ch // 出 chan
		fmt.Println(val)
	}()
	time.Sleep(1 * time.Second)
	fmt.Println("main end")
}

输出:

main start
a
main end

这就对了。

再看一个例子:

func main() {
	fmt.Println("main start")
	ch := make(chan string)
	go func() {
		ch <- "a" // 入 chan
	}()
	go func() {
		val := <- ch // 出 chan
		fmt.Println(val)
	}()
	time.Sleep(1 * time.Second)
	fmt.Println("main end")
}

输出:

main start
a
main end

再看一个例子:

func producer(ch chan string) {
	fmt.Println("producer start")
	ch <- "a"
	ch <- "b"
	ch <- "c"
	ch <- "d"
	fmt.Println("producer end")
}

func main() {
	fmt.Println("main start")
	ch := make(chan string, 3)
	go producer(ch)

	time.Sleep(1 * time.Second)
	fmt.Println("main end")
}

输出:

main start
producer start
main end

带缓冲的通道,如果长度等于缓冲长度时,再进就会阻塞。

再看一个例子:

func producer(ch chan string) {
	fmt.Println("producer start")
	ch <- "a"
	ch <- "b"
	ch <- "c"
	ch <- "d"
	fmt.Println("producer end")
}

func customer(ch chan string) {
	for {
		msg := <- ch
		fmt.Println(msg)
	}
}

func main() {
	fmt.Println("main start")
	ch := make(chan string, 3)
	go producer(ch)
	go customer(ch)

	time.Sleep(1 * time.Second)
	fmt.Println("main end")
}


//这里并不会发生阻塞,应为在携程customer中消费了producer中的chan

输出:

main start
producer start
producer end
a
b
c
d
main end

通道总结

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值