1、goroutine的基本语法
goroutine 是Go语言中的轻量级线程实现,由Go运行时(runtime)管理。Go程序会智能的将 goroutine中的任务合理地分配给每个CPU。Go程序从main包的main()函数开始,在程序启动时,Go程序就会为main()函数创建一个默认的 goroutine。
package mainimport ("fmt""time")func foo() {fmt.Println("foo 函数开始")time.Sleep(time.Second * 2)fmt.Println("foo 函数结束")}func bar() {fmt.Println("bar 函数开始")time.Sleep(time.Second * 3)fmt.Println("bar 函数结束")}func main() {startTime := time.Now().Unix()go foo() // 开启并行任务 foogo bar() // 开启并行任务 barendTime := time.Now().Unix()fmt.Println("消费时间,", endTime-startTime)}
2、sync.WaitGroup
Go语言中可以使用 sync.WaitGroup来实现并发任务的同步。sync.WaitGroup有以下几个方法:
| 方法名 | 功能 |
|---|---|
| (wg * WaitGroup) Add(delta int) | 计数器+delta |
| (wg *WaitGroup) Done() | 计数器-1 |
| (wg *WaitGroup) Wait() | 阻塞直到计数器变为0 |
sync.WaitGroup 内部维护着一个计数器,计数器的值可以增加和减少。例如当我们启动了N个并发任务时,就将计数器的值增加N。每个任务完成时通过调用Done()方法将计数器减1。通过调用Wait()来等待并发任务执行完,当计数器值为0时,表示所有并发任务已经完成。
package mainimport ("fmt""sync""time")func foo() {defer wg.Done() // 3. 计数器减去 1fmt.Println("foo 函数开始")time.Sleep(time.Second * 2)fmt.Println("foo 函数结束")}func bar() {defer wg.Done() // 3. 计数器减去 1fmt.Println("bar 函数开始")time.Sleep(time.Second * 3)fmt.Println("bar 函数结束")}var wg sync.WaitGroup // 1. 定义同步等待变量func main() {startTime := time.Now().Unix()wg.Add(2) // 2. 添加计数器funcData := [2]func(){foo, bar}for _, v := range funcData {go v()}wg.Wait() // 4.等待并发完毕endTime := time.Now().Unix()fmt.Println("消费时间,", endTime-startTime)}
3、GOMAXPROCS
Go运行时的调度器使用 GOMAXPROCS 参数来确定需要使用多少个OS线程来同时执行Go代码。默认值是机器上的CPU核心数。例如一个8核心的机器上,调度器会把Go代码同时调度到8个OS线程上(GOMAXPROCS是m:n调度中n)。
Go语言中可以通过 runtime.GOMAXPROCS()函数设置当前程序并发时占用的CPU逻辑核心数。
Go1.5版本之前,默认使用的是单核执行。Go1.5版本之后,默认使用全部CPU逻辑核心数。
我们可以通过将任务分配到不同的CPU逻辑核心上实现并行的效果,这里举个例子:
func main() {startTime := time.Now().Unix()wg.Add(2)fmt.Println(runtime.NumCPU()) // 查看cpu的个数runtime.GOMAXPROCS(1) // 并发跑1核funcData := [2]func(){foo, bar}for _, v := range funcData {go v()}wg.Wait()endTime := time.Now().Unix()fmt.Println("消费时间,", endTime-startTime)}

