Parts of A Tour Of Go
Go程 Goroutine
Go程是由Go运行时管理的轻量级线程。
1 | // 会启动一个新的Go程并执行 f(x, y, z) |
Go程在相同的地址空间中运行,因此在访问共享内存时必须进行同步。sync包提供了这种能力。
1 | package main |
信道channel
信道是带有类型的管道
信道使用信道操作符<-来发送值或接收值<-箭头指向就是数据流的方向
1 | // 信道在使用前必须创建 |
默认情况下,发送和接收操作在另一端准备好之前都会阻塞(同步调用)
1 | package main |
信道缓冲
信道是可以带缓冲的
将缓冲长度作为第二个参数提供给make来初始化一个带缓冲的信道
1 | ch := make(chan int, 100) |
仅当信道的缓冲区填满后,向其发送数据时才会阻塞(等待数据取出)
当缓冲区为空时,接收方会阻塞(等待数据到达)
1 | package main |
range和close
发送者可通过close关闭一个信道来表示没有需要发送的值了
1 | // 接收者可以通过为接收表达式分配第二个参数来测试信道是否被关闭 |
循环for i := range ch会不断从信道接收值,直到ch被关闭
注意:
- 建议由发送者关闭信道,而不是接收者
- 向一个已经关闭的信道发送数据会报错
panic - 信道与文件不同,通常情况下也无需关闭它们
- 只有在必须告诉接收者不再有值需要发送的时候才有必要关闭,例如终止
range循环
1 | package main |
select语句
select语句使一个Go程可以等待多个通信操作select会阻塞到某个分支可以继续执行为止,并执行该分支
当多个分支都准备好时会随机选择一个执行
1 | package main |
select默认选择
当select中的其它分支都没有准备好时,default分支就会执行
为了在尝试发送或接受时不发生阻塞,可使用default分支
1 | select { |
1 | package main |
练习: 等价二叉树
1 | // tree 包 |
函数tree.New(k)用于构造一个随机结构的二叉树,保存了值(k,2k,3k…10k)
1 | package main |
sync.Mutex互斥锁
信道非常适合在各个Go程间进行通信
要实现每次只有一个Go程能访问一个共享的变量,为了避免冲突,可以使用互斥锁Go标准库提供了sync.Mutex互斥锁类型 和 Lock Unlock两个方法
可以在代码前调用Lock方法,在代码后调用Unlock方法来保证一段代码的互斥执行
也可以用defer语句来保证互斥锁一定会被解锁
1 | package main |
练习: Web爬虫
使用Go的并发特性来并行化一个Web爬虫
修改Crawl函数来并行抓取URL,并保证不重复
可以用一个map来缓存已经获取的URL,但是map本身并不是并发安全的
1 | package main |