下篇更精彩!
1.明白几个概念:
串行:
同一时刻,只有一条指令,在一个cpu上执行,后面的指令需要等到前面的指令完成之后才能执行
也就是说,程序中接口请求是一个执行完成之后,紧接着执行下一个
并行:
同一时刻,有多条指令,在多个cpu上执行,也就是说,多个接口同时请求服务器获取数据
并发:
同一时刻,在一条指令,在一个cpu上执行,但是cpu可以快速的在多条指令之间来回切换执行.
程序:
编编译之后保存在磁盘上的二进制文件,会占用磁盘空间,但不会占用系统资源.
进程:
程序在操作系统中一次执行过程,比如打开某个桌面应用,系统会开启一个进程,同一个程序可以打开多次,也就是说可以出现多个进程,进程与进程之间互不影响
线程:
线程是进程中的一个执行实例,也就是说进程开启的同时会自动创建一个线程,主线程,进程中除了主线程,可以创建多个线程,也就是我们常说的多线程
协程:
协程是轻量级的线程,一个线程中可以有任意多个协程,但某一时刻只能有一个协程在运行.
复制代码
2.go中怎么开启协程:
func say() {
for i := 0; i < 20; i++{
fmt.Println("正在----说话")
}
}
func eat() {
for i := 0; i < 20; i++{
fmt.Println("正在++++++吃饭")
}
}
func main() {
go say()
go eat()
// 一旦主线程结束了, 那么程序就关闭了, 那么进程就不见了, 那么协程就不会被执行了
for{
;
}
}复制代码
3.怎么退出协程
func say() {
for i := 0; i < 20; i++{
fmt.Println("正在----说话")
if i== 5 {
runtime.Goexit()
}
}
}
func eat() {
for i := 0; i < 20; i++{
fmt.Println("正在++++++吃饭")
}
}
func main() {
go say()
go eat()
// 一旦主线程结束了, 那么程序就关闭了, 那么进程就不见了, 那么协程就不会被执行了
for{
;
}
}复制代码
4.如果同时开启多个协程,并且协程访问同一资源,那怎么保证不出错
需求1: 定义个打印的函数, 可以逐个的打印传入字符串的每个字符,在两个协程中调用这个好方法, 并且还要保持输出的内容有序的
复制代码
//创建一个互斥锁
var lock = sync.Mutex{}
func printChar(str string) {
//加锁,让别的协程无法访问
lock.Lock()
for _, ch := range str{
fmt.Printf("%c",ch)
time.Sleep(time.Microsecond * 300)
}
//解锁,让别的协程能访问
lock.Unlock()
}
func people1() {
printChar("hello")
}
func people2() {
printChar("world")
}
func main() {
go people1()
go people2()
// 一旦主线程结束了, 那么程序就关闭了, 那么进程就不见了, 那么协程就不会被执行了
for{
;
}
}复制代码
需求2:定义一个生产函数写入数据到数组,同时一个消费函数输出数组的数据,保证先生产,后消费复制代码
var buff [10] int
var lock = sync.Mutex{}
func producer() {
lock.Lock()
//种随机种子
rand.Seed(time.Now().UnixNano())
for i := 0; i < 10; i++ {
num := rand.Intn(100)
fmt.Println("生产者生产了", num)
//添加随机数
buff[i] = num
time.Sleep(time.Millisecond * 300)
}
lock.Unlock()
}
func consumer() {
lock.Lock()
for i:=0; i<10;i++ {
num := buff[i]
fmt.Println("-------消费者消费到了", num)
time.Sleep(time.Millisecond * 300)
}
lock.Unlock()
}
func main() {
go producer()
go consumer()
// 一旦主线程结束了, 那么程序就关闭了, 那么进程就不见了, 那么协程就不会被执行了
for{
;
}
}
注意点: 看上去通过给生产者以及消费者同时加锁就能解决, 只有生产完了才能消费 但是取决于谁想执行加锁操作, 所以不完美.复制代码