一、死锁
* 在主goroutine中向无缓存channel添加内容或在主goroutine中向channel添加内容且添加内容的个数已经大于channel缓存个数就会产生死锁
fatal error : all goroutines are asleep -deadlock!
* 死锁:在程序中多个进程(Golang中goroutine)由于相互竞争资源而产生的阻塞(等待)状态,而这种状态一直保持下去,此时称这个线程是死锁状态
* 在Golang中使用无缓存channel时一定要注意.以下是一个最简单的死锁程序
* 主协程中有ch<-1,无缓存channel无论添加还是取出数据都会阻塞goroutine,当前程序无其他代码,主goroutine会一直被阻塞下去,此时主goroutine就是死锁状态
func main() {
ch := make(chan int)
ch <- 1
}
* 而下面代码就不会产生死锁
* 通过代码示例可以看出,在使用无缓存channel时,特别要注意的是在主协程中要操作channel代码
func main() {
ch := make(chan int)
go func() {
ch <- 1
fmt.Println("执行goroutine")
}()
time.Sleep(5e9)
fmt.Println("程序执行结束")
}
二、有缓存通道
* 创建一个有缓存通道
func main() {
ch := make(chan int, 3) //缓存大小3,里面消息个数小于等于3时都不会阻塞goroutine
ch <- 1
ch <- 2
ch <- 3
ch <- 4 //此行出现死锁,超过缓存大小数量
}
* 在Golang中有缓存channel的缓存大小是不能改变的,但是只要不超过缓存数量大小,都不会出现阻塞状态
func main() {
ch := make(chan int, 3) //缓存大小3,里面消息个数小于等于3时都不会阻塞goroutine
ch <- 1
fmt.Println(<-ch)
ch <- 2
fmt.Println(<-ch)
ch <- 3
ch <- 4
fmt.Println(len(ch))//输出2,表示channel中有两个消息
fmt.Println(cap(ch))//输出3,表示缓存大小总量为3
}
三、select简介
* Golang中select和switch结构特别像,但是select中case的条件只能是I/O
* select 的语法(condition是条件)
select{
case condition:
case condition:
default:
}
* select执行过程:
* 每个case必须是一个IO操作
* 哪个case可以执行就执行哪个
* 多个case都可以执行,随机执行一个
* 所有case都不能执行时,执行default
* 所有case都不能执行,且没有default,将会阻塞
func main() {
runtime.GOMAXPROCS(1)
ch1 := make(chan int, 1)
ch2 := make(chan string, 1)
ch1 <- 1
ch2 <- "hello"
select {
case value := <-ch1:
fmt.Println(value)
case value := <-ch2:
fmt.Println(value)
}
}
* select多和for循环结合使用,下面演示出了一直在接收消息的例子
func main() {
ch := make(chan int)
for i := 1; i <= 5; i++ {
go func(arg int) {
ch <- arg
}(i)
}
//如果是一直接受消息,应该是死循环for{},下面代码中是明确知道消息个数
for i := 1; i <= 5; i++ {
select {
case c := <-ch:
fmt.Println("取出数据", c)
default:
//没有default会出现死锁
}
}
fmt.Println("程序执行结束")
}
* break可以对select生效,如果for中嵌套select,break选择最近结构
四、GC
* GC英文全称 garbage collector
* Go语言GC是相对C/C++语言非常重要的改进
* 一些常用GC算法
* 引用计算法:当对象被引用时计算器加一.不被引用计数器减一
* PHP和Object-C使用
* 相互引用无法回收
* 计数增加消耗
* Mark And Sweep 标记和清除算法:停止程序运行,递归遍历对象,进行标记。标记完成后将所有没有引用的对象进行清除
* 由于标记需要停止程序(Stop the world),当对象特别多时,标记和清除过程比较耗时(可能几百毫秒),很难接受
* 三色标记法:是Mark And Sweep的改进版.从逻辑上分为白色区(未搜索),灰色区(正搜索),黑色区(已搜索).灰色区内容是子引用没有进行搜索,黑色区表示子引用存在
* 分代收集:一般情况都有三代,例如java中新生代,老年代,永久代.当新生代中带有阈值时会把对象放入到老年代,相同道理老年代内容达到阈值会放入到永久代
五、Go语言中的GC
* Go语言中采用Stop The World方式
* Golang每个版本基本上都会对GC进行优化,从Golang1.5开始支持并发(concurrent )收集,从1.8版本已经把STW时间优化到了100微妙,通常只需要10微秒以下.且在1.10版本时再次优化减少GC对CPU占用
* Go语言中GC是自动运行的,在下列情况下会触发GC
* 当需要申请内存时,发现GC是上次GC两倍时会触发
* 每2分钟自动运行一次GC
* GC调优
* 小对象复用,局部变量尽量少声明,多个小对象可以放入到结构体,方便GC扫描
* 少用string的”+”