一.Go 语言进阶与依赖管理
1.1并发和并行
Go可以充分发挥多核优势,高效运行。
多线程程序在单核心的 cpu 上运行,称为并发;
多线程程序在多核心的 cpu 上运行,称为并行。
并发与并行并不相同,并发主要由切换时间片来实现“同时”运行,并行则是直接利用多核实现多线程的运行,Go程序可以设置使用核心数,以发挥多核计算机的能力。
1. 2 线程
进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。
线程是进程的一个执行实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
一个进程可以创建和撤销多个线程,同一个进程中的多个线程之间可以并发执行。
协程:用户态,轻量级线程,栈 MB 级别。
线程:内核态,线程跑多个协程,栈 KB 级别。
1.2.1 快速打印(协程)
go语言开启协程十分简单,只需要在函数的前面写上go关键字即可。
func hello(i int) {
println("helle :" + fmt.Sprint(i))
}
func main() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
使用time.Sleep(time.Second)来阻塞主函数,来防止主函数退出进程。
可以看到,是乱序输出的。
通过并行来打印的输出。
1.2.2 协程通信共享内存
go语言的最大两个亮点,一个是goroutine,一个就是channel了。二者合体的典型应用CSP,基本就是大家认可的并行开发神器,简化了并行程序的开发难度。
Go 通过 channel 实现 CSP 通信模型,主要用于 goroutine 之间的消息传递和事件通知。 有了 channel 和 goroutine 之后,Go 的并发编程变得异常容易和安全,得以让程序员把注意力留到业务上去,实现开发效率的提升。
1.2.3 channel
Channel是Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯(communication)。
它的操作符是箭头 <- 。
容量表示通道最多可容纳的元素数,并表示通道的缓存大小。
如果未设置容量,或容量设置为0,则表示通道没有缓存,只有当发送方和接收方准备就绪时,才会进行通信。如果设置了缓存,则可能不会发生阻塞。只有当缓冲区已满时,发送才会阻止,而只有当缓存为空时,接收才会阻止。零信道无法通信。
可以通过内置的close方法关闭通道。
可以在多个goroutine中从信道接收/向信道发送数据,而无需考虑额外的同步措施。
信道可以用作先进先出(FIFO)队列,接收数据和发送数据的顺序是一致的。
package main
func main() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
println(i)
}
}
容量表示通道可以容纳的最大元素数,并表示通道的缓存大小。
如果容量未设置或设置为0,则表示通道没有缓存。只有当发送者和接收者准备好了,他们才能进行通信。如果设置了缓存,则可能不会发生阻塞。只有当缓冲区已满时,发送才会被阻止,而只有在缓冲区为空时,接收才会被阻止。零通道无法通信。
可以通过内置的close方法关闭通道。
可以在多个goroutine中从/向通道接收/发送数据,而无需考虑额外的同步措施。
该信道可以用作先进先出(FIFO)队列,并且接收数据和发送数据的顺序是一致的。