文章目录
- Go学习-Day8
- 单元测试
- Goroutine
- 进程和线程
- 并发和并行
- Go协程和主线程
- MPG模式
- CPU相关
- 协程并行的资源竞争
Go学习-Day8
- 个人博客:CSDN博客
单元测试
-
testing框架会将xxx_test.go的文件引入,调用所有TestXxx的函数
-
在cal_test.go文件里面写这个
-
package main import "testing" func TestAdd(t *testing.T) { a, b := 1, 2 if add(a, b) != 4 { t.Fatalf("Wrong Answer!") } }
-
在cal.go文件里写这个
-
package main func add(a int, b int) int { return a + b }
-
运行go test -v的命令,就能运行单测
-
可以得到结果
-
=== RUN TestAdd cal_test.go:8: Wrong Answer! --- FAIL: TestAdd (0.00s)
-
testing框架import这个test文件之后,会调用所有TestXxx的函数,注意大写!
Goroutine
进程和线程
- 进程是程序的在操作系统的一次执行过程
- 线程是比进程更小的单位,一个进程能创建销毁多个线程
- 一个程序至少有一个进程,一个进程至少有一个线程
并发和并行
- 多线程在单核上运行,就是并发
- 多线程在多核上运行,就是并行
Go协程和主线程
-
主线程类似进程
-
协程类似线程,是轻量级的线程
-
协程的特点
- 有独立的空间
- 共享程序的堆空间
- 调度由用户控制
- 协程是轻量级的线程
-
import ( "fmt" "strconv" "time" ) func test() { for i := 0; i < 5; i++ { fmt.Println("test() calls! " + strconv.Itoa(i)) time.Sleep(time.Second) } } func main() { go test() for i := 0; i < 5; i++ { fmt.Println("main() calls! " + strconv.Itoa(i)) time.Sleep(time.Second) } }
-
输出
-
main() calls! 0 test() calls! 0 test() calls! 1 main() calls! 1 main() calls! 2 test() calls! 2 test() calls! 3 main() calls! 3 main() calls! 4 test() calls! 4
-
go关键字会另起一个协程,主线程执行到这里会开一个协程并行执行,如果主线程执行完毕退出,协程会被强制退出
MPG模式
-
M(Machine)是操作系统的主线程,也就是物理线程
-
P(Processor)协程执行的上下文
-
G(Gorountine)协程
-
Go语言的协程是轻量级的,是逻辑态的,可以起上万个协程;而C/java的多线程是内核态的,几千个就会耗光CPU
CPU相关
runtime.NumCPU()
//获取本地CPU数目
runtime.GOMAXPROCS(int)
//设置GO最大可用的CPU数目
//Go Max Processors
协程并行的资源竞争
-
多个协程同时访问一个资源会发生冲突,会发生并发问题
-
在java中我们有锁和原子类来保证并发安全
-
声明一个全局锁变量lock
-
lock sync.Mutex //sync是同步的意思,Muti-excluded互斥锁?
-
lock.Lock()//在进行并发的读写操作的时候,先上个锁 ...//在进行操作的时候,别的协程会排队等待 lock.Unlock()//解锁之后,才能给别的协程使用
-
主线程读的时候也需要加锁,因为底层不知道协程已经解锁了,会发生资源冲突
-
但是这样不同协程之间没办法通讯,不知道什么时候协成完成任务了,白白空转浪费时间,或者提前结束主线程,终止协程,管道可能能解决这些问题,明天再学