go语言中的并发和channel的理解

在学习go语言过程中,有一个比较难以理解的知识点就是并发(go routine)以及通信通道(channel)。channel是为了使go语言更高效地并发,避免容易出错,避免负责的共享内存操作,而设计出来的。但是我们在编写代码过程中,经常出现死锁。那么,有没有一种比较容易理解的方式来理解go routine, chan之间的关系,从而避免死锁呢?有的,可以以一种简单的思路理解死锁是如何产生的。
简单地说,就是go routine必须在main函数使用chan之前。
先看下面4个例子:
例子1
package main
import (
“fmt”
)
func f1(in chan int) {
in <- 2
}
func main() {
out := make(chan int)
go f1(out)
fmt.Println(<-out)
}
运行结果:2。正常运行,go routine在main使用chan之前调用。
例子2
package main
import (
“fmt”
)
func f1(in chan int) {
in <- 2
}
func main() {
out := make(chan int)
fmt.Println(<-out)
go f1(out)
}
运行结果:fatal error: all goroutines are asleep - deadlock!
main函数在go routine之前使用chan
例子3
package main
import (
“fmt”
)
func f1(in chan int) {
fmt.Println(<-in)
}
func main() {
out := make(chan int)
out <- 2
go f1(out)
}
运行结果:fatal error: all goroutines are asleep - deadlock!
例子4
package main
import (
“fmt”
)
func f1(in chan int) {
fmt.Println(<-in)
}
func main() {
out := make(chan int)
go f1(out)
out <- 2
}
运行结果:2

进一步思考,如果使用chan的代码都是放在go routine,那会怎样呢?答案是:正常。
例子5
package main
import (
“fmt”
“time”
)
func f1(in chan int) {
in <- 2
}
func f2(ch chan int) {
fmt.Println(<-ch)
}
func main() {
out := make(chan int)
go f2(out)
go f1(out)
time.Sleep(1 * time.Second)
}
运行结果:2
例子6
package main
import (
“fmt”
“time”
)
func f1(in chan int) {
in <- 2
}
func f2(ch chan int) {
fmt.Println(<-ch)
}
func main() {
out := make(chan int)
go f1(out)
go f2(out)
time.Sleep(1 * time.Second)
}
运行结果:2
其中例子5和6中的main函数都在最后添加睡眠等待函数,睡眠1秒,这个是等待go routine完成,避免main函数直接退出。

总之一句:go routine必须在main函数使用chan之前。这种简易的理解方式可以扩展一下,那就是main函数在使用chan时(其实就是堵塞通信),应该要有go routine活着。
请看例子7
package main
import (
“fmt”
)

func main() {
forever := make(chan int)
go func() {
fmt.Println(“In the go routine.”)
}()

fmt.Println(“In the main, waiting forever.”)
<-forever
}
在这个例子中,只有main函数使用了forever这个chan。go routine打印一行语句就直接退出,相当于没有。
运行结果:
In the main, waiting forever.
In the go routine.
fatal error: all goroutines are asleep - deadlock!

同理,例子8
package main
import (
“fmt”
“time”
)

func main() {
forever := make(chan int)
go func() {
for true {
fmt.Println(“In the go routine.”)
time.Sleep(3 * time.Second)
}
}()

fmt.Println(“In the main, waiting forever.”)
<-forever
}
由于main函数等待forever这个永远没有输入的通信输出,永远等不到,但是go routine一直无限循环,所以一直运行下去。这个是很多服务器的写法。
运行结果:
In the main, waiting forever.
In the go routine.
In the go routine.
。。。。。

你看go语音的go routine,channel,和死锁之间的关系就是这么简单!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值