一:gorouting的必要性

假如设计一个程序1-10000000000000数字之间那些是偶数

①:传统思路上设计一个循环,在循环中判断

②:使用并发或者并行的方法,将判断那些书偶数的任务分配给多个grouting去完成,这样将大大提高速率。

 二:进程与线程

①:进程就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位;

②:线程是进程的一个执行实例,是程序执行的最小单位,他是比进程更小的能独立运行的基本单位;

③:一个进程可以创建和销毁多个线程,同一个进程中的多个线程可以并发执行;

④:一个程序至少有一个进程,一个进程至少有一个线程;

⑤:举例说明,在电脑上启动百度云客户端就是启动一个百度云进程,当利用百度云客户端下载一个文件时,就会创建一个下载线程,当下载10个文件时就会创建10个下载线程。

三:并发和并行

①:多线程程序在单核cpu上运行就是并发;

②:多线程程序在多核cpu上运行就是并行;

③:示意图

Go之gorouting 高并发实现_Go

四:Go协程和Go主线程

 Go主线程(也可以理解为进程),一个Go线程可以有多个协程。

①:Go协程的特点:有独立的栈空间、共享程序堆空间、调度由用户控制、协程是轻量级的线程

②:原理示意图

Go之gorouting 高并发实现_Go_02

五:gorouting使用举例

①:

package main

import (
"fmt"
"strconv"
"time"
)
func gr() {
for i := 1; i <= 3; i++{
fmt.Println("hello gr"+strconv.Itoa(i))
time.Sleep(time.Nanosecond)
}
}

func main() {
go gr()
for i := 1; i <= 3; i++{
fmt.Println("hello main"+strconv.Itoa(i))
time.Sleep(time.Nanosecond)
}
}
结果
[ `go run gorouting.go` | done ]
hello main1
hello gr1
hello gr2
hello main2
hello main3
hello gr3

 由有代码可知main主线程和gr()协程同时执行

②:主线程与协程原理图

Go之gorouting 高并发实现_主线程_03

③:总结

主线程是一个物理线程,直接作用在cpu上,是重量级的,非常耗费资源;

协程从主线程开启,是轻量级的线程,是逻辑态。资源耗费较小;

golang的协程机制是重要特点,可以轻松的开启上万个协程,其他语言并发机制一般是基于线程的,开启过多线程会导致资源耗费大。

六:gorouting的MPG的调度模式

①:基本介绍

M:操作系统的主线程(物理线程)

P:协程执行树妖的条件(如是否有足够的cpu资源等等)

G:协程

②:MPG的第一种运行状态

Go之gorouting 高并发实现_主线程_04

当前有三个M,如果三个M在同一个cpu运行,就是并发,如果在不同cpu运行就是并行;

M1,M2,M3正在执行一个协程G,M1的协程队列有三个协程等待调用执行,M2同M2,M3有两个

由上图可知Go协程是轻量级的线程,是逻辑态,Go可以轻松起上上万协程

其他编程c/java的多线程,往往是内核的,比较重量级,几千个就可能耗光cpu资源

③:MPG的第二种运行状态

Go之gorouting 高并发实现_主线程_05

M0主线程正在执行G哦协程,另外三个协程在队列等待被执行;

如果G0即正在执行的协程阻塞,如读出数据库等;

这时就会创建M1主线程(也可能是从已有的线程池中取出M1),并且将在等待的3个协程挂到M1上并开始执行,M0的主线程任然执行G0;

这样的MPG调度模式既可以让G0继续执行,又不会让队列的其他协程一直被阻塞,任然可以并发或并行执行;

等到G0执行完毕,M0会被放到空闲的主线程或继续执行其他协程

七:设置Go的运行cpu数

①:go1.8后,默认程序运行在多个核上。

②:go1.8前,默认只运行在一个核,需要设置才可以更高效的利用cpu

package main
import (
"fmt"
"runtime"
)
func main() {
//获取当前系统cpu的数量
num := runtime.NumCPU()
//设置go运行程序的核实
runtime.GOMAXPROCS(num)
fmt.Println("cpu核数:",num)
}
结果
[ `go run gorouting.go` | done ]
cpu核数: 4