进程和线程
进程(Process)就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基 本单位,进程是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进 程都有一个自己的地址空间。一个进程至少有 5 种基本状态,它们是:初始态,执行态, 等待状态,就绪状态,终止状态,通俗的讲进程就是一个正在执行的程序。
线程 是进程的一个执行实例,是程序执行的最小单元,它是比进程更小的能独立运行的基 本单位
一个进程可以创建多个线程,同一个进程中的多个线程可以并发执行,一个程序要运行的话至少有一个进程
并发和并行
并发:多个线程同时竞争一个位置,竞争到的才可以执行,每一个时间段只有一个线程在执
行。
并行:多个线程可以同时执行,每一个时间段,可以有多个线程同时执行。
通俗的讲多线程程序在单核 CPU 上面运行就是并发,多线程程序在多核 CUP 上运行就是并行,如果线程数大于 CPU 核数,则多线程程序在多个 CPU 上面运行既有并行又有并发
协程goroutine
golang 中的主线程:(可以理解为线程/也可以理解为进程),在一个 Golang 程序的主线程 上可以起多个协程。Golang 中多协程可以实现并行或者并发
协程:可以理解为用户级线程,这是对内核透明的,也就是系统并不知道有协程的存在,是 完全由用户自己的程序进行调度的。Golang 的一大特色就是从语言层面原生支持协程,在 函数或者方法前面加 go 关键字就可创建一个协程。可以说 Golang 中的协程就是 goroutine
多协程和多线程:Golang 中每个 goroutine (协程) 默认占用内存远比 Java 、C 的线程少
OS 线程(操作系统线程)一般都有固定的栈内存(通常为 2MB 左右)
一个 goroutine (协程) 占用内存非常小,只有 2KB 左右,多协程 goroutine 切换调度开销方面远比线程要少
使用协程
func test() {
for i := 0; i <= 10; i++ {
fmt.Println(i)
}
}
func main() {
// go关键字声明这是一个协程,test方法代码和主进程代码同时指向
// 如果主进程执行完了,整个程序就结束了,协程没有执行完也不执行了,如果协程执行完主进程没有执行完,主进程会继续执行
go test()
for i := 0; i <= 10; i++ {
fmt.Println(i)
}
}
sync.WaitGroup 等待协程
import (
"fmt"
"sync"
)
// 需要导入sync包
// 声明WaitGroup
var wg sync.WaitGroup
func test() {
for i := 0; i <= 10; i++ {
fmt.Println(i, "123")
}
wg.Done() // 协程计数器-1
}
func main() {
wg.Add(1) // 协程计数器+1,
go test()
for i := 0; i <= 10; i++ {
fmt.Println(i)
}
wg.Wait() // 等待协程执行完毕,启动一个协程登记+1,结束就-1,等于0 的时候就等待结束