最近在看goroutine协程有关的知识,顺便做一个笔记记录下来。
goroutine协程
1)进程是程序在操作系统中的一次执行过程,是系统进行进行资源分配和调度的基本单位;
2)线程是进程的一个执行实例,是程序执行的最小单位(比进程更小的能独立运行的基本单位);
3)一个进程可以创建和销毁多个线程,同一个进程中的多个线程可以并发执行;
4)一个程序至少有一个进程,一个进程至少有一个线程;
并行和并发:
1)并发:多线程程序在单核上运行;微观上来看,某一个时间点只有一个任务在执行;
2)并行:多线程程序在多核上运行;微观上来看,某一个时间点有多个任务同时在执行。因此,并行的速度比并发快。
Go协程和Go主线程
1)Go主线程(可以理解为线程/进程):一个Go线程上,可以起多个协程,可以理解为协程是轻量级的线程(编译器做优化);
2)Go协程的特点: 有独立的栈空间; 共享程序堆空间; 调度由用户控制; 协程是轻量级的线程;
如果主线程退出了,则协程即使没有执行完毕, 也会直接退出;协程也可以在主线程没有结束前,完成任务并退出。
3)总结: 主线程是一个物理线程,直接作用在CPU上,是重量级的,非常耗费CPU资源; 协程是从主线程开启的,是轻量级的线程,是逻辑态,对资源的消耗相对小; golang的协程机制是重要的特点,可以轻松开启上万个协程;其他编程语言的并发是基于线程的,开启过多的线程会对资源消耗巨大,这就凸现了golang在并发上的优势;
举例:
package main
import (
"fmt"
"runtime"
"strconv"
"time"
)
func test() {
for i := 1; i < 10; i++ {
fmt.Println("hello world" + strconv.Itoa(i))
time.Sleep(time.Second)
}
}
func main() {
num := runtime.NumCPU()
fmt.Printf("the number of CPU is %d\n", num)
runtime.GOMAXPROCS(num) // 设置最大可以调度的CPU的个数
go test() // 开启了一个协程
for i := 1; i < 10; i++ {
fmt.Println("hello golang" + strconv.Itoa(i))
time.Sleep(time.Second)
}
}
goroutine协程存在的问题
- 用
goroutine协程,来实现并行和并发,如何实现不同协程间的通信; - 由于没有对全局变量加锁,故在程序在运行时,可能存在资源竞争的问题(如concurrent map writes)(通过
go build -race main.go来检查);
package main
import "fmt"
var map_ map[int]int = make(map[int]int, 200)
func Factorial(n int) {
var res int
for i := 1; i < n; i++ {
res *= i
}
map_[n] = res
}
func main() {
for i := 0; i < 200; i++ {
go Factorial(i)
}
for index, val := range map_ {
fmt.Printf("map[%d]=%d\n", index, val)
}
}