goroutine(协程)
进程和线程的说明
- 进程就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位
- 线程是进程的一个执行实例,是程序执行的最小单元,它是比进程更小的能独立运行的基本单位。
- 一个进程可以创建和销毁多个线程,同一个进程中的多个线程可以并发执行。
- 一个程序至少有一个进程,一个进程至少有一个线程
![image-20220206173923616](https://i-blog.csdnimg.cn/blog_migrate/7c6e6a26a7bcbd4a1096b5091f8ea1f4.png)
并发和并行
多线程程序在单核上运行,就是并发
多线程程序在多核上运行,就是并行
![image-20220206173817250](https://i-blog.csdnimg.cn/blog_migrate/5522026d0d07a2ee57597beb906eceb9.png)
![image-20220206193954643](https://i-blog.csdnimg.cn/blog_migrate/77db58a738c4295df0382ea71adaec3c.png)
Go协程和Go主线程
Go主线程(有程序员直接称为线程/也可以理解成进程):一个Go线程上,可以起多个协程,你可以这样理解,协程是轻量级的线程。
![image-20220206194529873](https://i-blog.csdnimg.cn/blog_migrate/b0cd05e5403dc478d3a2529328c7c42c.png)
Go协程的特点
- 有独立的栈空间
- 共享程序堆空间
- 调度由用户控制
- 协程是轻量级的线程
入门案例
package main
import (
"fmt"
"strconv"
"time"
)
//在主线程(可以理解成进程)中,开启一个goroutine,该协程每隔1秒输出“hello,world""
//在主线程中也每隔一秒输出"hello,golang",输出10次后,退出程序
//要求主线程和goroutine同时执行
//编写一个函数,每隔1秒输出 “hello,world”
func test() {
for i := 1; i <= 10; i++ {
fmt.Println("test() hello,world" + strconv.Itoa(i))
time.Sleep(time.Second)
}
}
func main() {
go test() //开启协程
for i := 1; i <= 10; i++ {
fmt.Println("main() hello,golang" + strconv.Itoa(i))
time.Sleep(time.Second)
}
}
![image-20220206195705032](https://i-blog.csdnimg.cn/blog_migrate/66e29072a9c5765ba3b6954ae9389450.png)
![image-20220206195843453](https://i-blog.csdnimg.cn/blog_migrate/cc308adf70cfeb89cb2228e8665d5f85.png)
- 主线程是一个物理线程,直接作用在cpu上的。是重量级的,非常耗费cpu资源。
- 协程从主线程开启的,是轻量级的线程,是逻辑态。对资源消耗相对小。
- Golang的协程机制是重要的特点,可以轻松的开启上万个协程。其它编程语言的并发机制是一般基于线程的,开启过多的线程,资源耗费大,这里就突显Golang在并发上的优势了
gproutine的调度模型(MPG)
M:操作系统的主线程
P:协程执行需要的上下文
G:协程
![image-20220206201113522](https://i-blog.csdnimg.cn/blog_migrate/a1ab0a4579df074aa780b0aa7cb84225.png)
![image-20220206201144512](https://i-blog.csdnimg.cn/blog_migrate/e3282a43658df8bad54b5550819a677d.png)
设置Golang运行的cpu数
package main
import (
"fmt"
"runtime"
)
func main() {
cpuNum := runtime.NumCPU()
fmt.Println("cpuNum = ", cpuNum)
//可以自己设置使用多个cpu
runtime.GOMAXPROCS(cpuNum - 1)
}