go 语言入门指南:基本语法和常用特性解析
一.协程 goroutine
goroutine的引入,从一个需求出发。需求:要求统计1-900000000000的数字中,哪些是素数?
分析思路: 1)传统的方法,就是使用一个循环,循环的判断各个数是不是素数。(很慢的) 2)使用并发或者并行的方式,将统计素数的任务分配给多个goroutine去完成,这个时候可以使用到goroutine
goroutine的基本介绍
进程和线程的区别
1)进程就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位。
2)线程是进程的一个执行实例,是程序执行的最小单元,它是比进程更小的能独立运行的基本单元。
3)一个进程可以创建和销毁多个线程,同一个进程中的多个线程可以并发执行
4)一个程序至少有一个进程,一个进程至少有一个线程
并发和并行
1)多线程程序在单核上运行,就是并发
2)多线程程序在多核上运行,就是并行
并发:因为是在一个cpu上,比如有10个线程,每个线程执行10毫秒(进行轮询操作),从人的角度看,好像这10个线程都在运行,但是从微观上看,在某一个时间点看,其实只有一个线程在执行,这就是并发。
并行:因为是在多个CPU上(比如8个CPU),比如有8个线程,每个线程执行10毫秒(各自在不同的CPU上执行),从人的角度看,这8个线程都在运行,但是从微观上看,在某一个时间点看,也同时有8个线程在执行,这就是并行。
GO协程和Go主线程
1)Go主程序(有程序员直接称为线程/也可以理解为进程);一个Go线程上,可以起多个协程,也可以这样理解,协程是轻量级的线程(编译器做优化)。
2)Go协程的特点
- 有独立的栈空间
- 共享程序堆空间
- 调度由用户控制
- 协程是轻量级的线程
goroutine-快速入门
案例:在主线程(可以理解为进程)中,开启一个goroutine,该协程每隔1s输出"hello,world".在主线程中每隔1s输出"hello golang",输出10s后,退出程序。要求主线程与goroutine同时执行
代码实现:
package main
import (
"fmt"
"strconv"
"time"
)
//编写函数 每隔1s输出 “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)
}
}
输出的效果是:main这个主线程和test协程同时执行
主线程和协程的执行示意图:
快速入门小结:
1) 主线程是一个物理线程,直接作用在CPU上的,是重量级的,非常耗费cpu资源。
2)协程从主线程开启的,是轻量级的线程,是逻辑态,对资源消耗相对小。
3)Golang的协程机制是重要的特点,可以轻松的开启上万个协程。其他编程语言的并发机制一般是基于线程的,开启过多的线程,资源消耗大,这里就突显Golang在并发上的优势了。
goroutine的调度模型
MPG模式基本介绍
1)M:操作系统的主线程(是物理线程) 2)P:协程执行需要的上下文 3)G: 协程
设置Golang运行的cpu数
介绍:为了充分利用多cpu的优势,在Golang程序中,设置运行的cpu数目
package main
import (
"fmt"
"runtime"
)
func main() {
//获取当前系统的CPU数目
num := runtime.NumCPU()
runtime.GOMAXPROCS(num)
fmt.Println("num=", num)
}
go1.8以后,默认让程序运行在多个核上,可以不用设置了。go1.8前,还是要设置一下,可以高效的利用cpu