前置基础
golang基本语言 编程基础 有并发经验更好
GoLang 核心优势 高性能的支撑 高并发
概览
基本概念:
进程Process 与线程 Thread
进程定义:进程 是并发执行的程序中分配和管理资源的基本单位。
线程定义:线程是进程的执行单元,是进行调度的实体,是比进程更小的独立运行单位。
并行Concurrent与并发Paralled
并发定义: 多线程交替操作同一资源类
并行定义:多个线程同时操作多个资源类
图解:
Erlang 之父 Joe Armstrong 用一张5岁小孩都能看懂的图解释了并发与并行的区别
协程 goroutine 的引入
需求 :
统计 1~2000000的数字中 哪些是素数
传统方式 :使用循环 判断,
优化:使用并发和并行的方式
“够浪”:将统计分配给多个 goroutine去完成
协程的基本概念:
协程:
协程是单线程下的并发,又称微线程,纤程。它是实现多任务的另一种方式,只不过是比线程更小的执行单元。因为它自带CPU的上下文,这样只要在合适的时机,我们可以把一个协程切换到另一个协程。英文名Coroutine。
一句话说明什么是协程:轻量级的线程 独立的栈空间 ,共享程序堆空间 调度由用户控制 是逻辑态,对资源消耗小
线程和协程的区别:
线程的切换是一个cpu在不同线程中来回切换,是从系统层面来,不止保存和恢复CPU上下文这么简单,会非常耗费性能。但是协程只是在同一个线程内来回切换不同的函数,只是简单的操作CPU的上下文,所以耗费的性能会大大减少。
golang的协程机制,可轻松开启上万个协程。其他语言并发机制一般基于线程,开启过多资源耗费大。
案例:
主线程开启一个 goroutine 每隔1s输出 “马士兵教育申专你好!”
在主线程中每隔 2s 输出 go routine 十次后退出程序
要求主线程和 goroutine同时执行
流程图:
百万级并发
package main
import (
"fmt"
"runtime"
)
var num int = 1
func main() {
// for i := 1; i < 10000000; i++ {
// //go runTimes(1)
// }
//1.8前 要设置 CPU 核心数 。 之后默认全开
runtime.GOMAXPROCS(16)
fmt.Println(runtime.NumCPU())
// for i := 1; i <= 10; i++ {
// fmt.Println("main", i, "马士兵教育申专你好!", 10-i)
// time.Sleep(time.Second * 2)
// }
}
func runTimes(times int) int {
for i := 1; i <= times; i++ {
fmt.Println("runTimes", i, "马士兵教育申专你好!", times-i)
fmt.Println("num: ", num)
// time.Sleep(time.Second)
}
num++
return times
}
并发的安全问题
import (
"fmt"
"time"
)
var (
testMap = make(map[int]int, 10)
)
func testNum(num int) {
res := 1
for i := 1; i <= num; i++ {
res *= i
}
testMap[num] = res
}
func main() {
start := time.Now()
for i := 1; i < 200; i++ {
go testNum(i)
}
//协程需要在main之后完毕