程序:一组二进制数据,不占用系统资源
进程:程序在操作系统上的一次执行过程。系统进行资源分配和调度的独立单位。
线程:进程的一个执行实体,CPU调度分派的基本单位。
个人理解:程序、进程和线程的关系。程序则是生产资料,进程则为工厂,线程就是工厂里的车间。生产资料不经过工厂加工,则无法得出实际产品。工厂的运作实际上就是靠车间的运作,工厂至少要有一个车间才能运作起来,大型工厂可以有多个车间。
并发:同一时间内执行多个任务(同时用微信和两个人聊天)
并行:同一时刻执行多个任务(两个人同时用微信和人聊天)
goroutine:Go语言中的一种机制,概念类似于线程。Go语言运行时(runtime)调度和管理。Go程序会智能地将 goroutine 中的任务合理地分配给每个CPU。
OS线程:操作系统线程,一般都有固定的栈内存(通常2MB)
一个goroutine的栈内存不固定,最小2KB,最大1GB。
OS线程和goroutine之间的关系:
- 一个OS线程对应用户态多个goroutine。
- go程序可以同时使用多个操作系统线程。
- goroutine和OS线程是多对多的关系,即m:n。
在调用函数是在其前面加上“go”关键字,即可为其创建一个goroutine
启动多个goroutine,和使用sync.WaitGroup来实现goroutine同步
var w sync,WaitGroup
func Hello(i int){
defer w.Done() //flag, 标记该函数执行结束
fmt.Println("Hello goroutine",i)
}
func main (){
for i := 0; i < 10; i++{
w.Add(1) //每for循环一次就启动一个goroutine
go Hello(i)
}
w.Wait()//等待Add()登记的goroutine结束
}
run.GOMAXPROCS(n):设置当前程序并发时占用的CPU逻辑核心数。n:CPU核心数。
单纯的奖函数并发执行是没有多大意义的,函数之间的通信才能体现并发函数的意义
channel:通道,是引用类型,空值为nil
定义格式:
var 变量名 chan 元素类型
var ch chan int
创建channel格式:
make(chan 元素类型, [缓冲大小])
ch := make(chan int, 128)
channel的操作:
- 发送(send):使用“<-”符号。
ch <- 10
- 接收(receive):使用“<-”符号。
x := <- ch
- 关闭:
close(ch)
channel关闭成功后,读取完数据后返回零值。
channel有缓冲区和无缓冲区的区别:
- 无缓冲区:也称同步通道,发送方和接收方必须同时进行,否则会阻塞,形成死锁。
- 有缓冲区:通道有容量存放元素,可以有效解决无缓冲区通道阻塞问题。
var w sync.WaitGroup
func receive(ch chan int) {
defer w.Done()
x := <-ch
fmt.Println("receive secceeded", x)
}
func main() {
ch := make(chan int)
for i := 0; i < 10; i++ {
w.Add(1)
go receive(ch)
ch <- i
}
w.Wait()
close(ch)
}
无缓冲区通道,必须先做好接收准备,才能发送,不然会形成阻塞
单向通道:我们可以限制通道(只能发送或者接收)
func counter(out chan<- int) {
for i := 0; i < 100; i++ {
out <- i
}
close(out)
}
func squarer(out chan<- int, in <-chan int) {
for i := range in {
out <- i * i
}
close(out)
}
func printer(in <-chan int) {
for i := range in {
fmt.Println(i)
}
}
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go counter(ch1)
go squarer(ch2, ch1)
printer(ch2)
}
互斥锁:一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源
var lock sync.Mutex
func add(){
for i := 0; i < 5000; i++ {
lock.Lock() // 加锁
x = x + 1
lock.Unlock() // 解锁
}
}