了解计算机原理
- 进程:计算机资源分配单位
- 线程:cpu处理单位
- 协程:以 特殊机制或者函数实现高并发,又称 轻量级线程
了解Goroutine
- Go Goroutine, go语言中的协程,实现并发。
- 关键字 go
- 初始大小 4k,随着程序执行自动增长和删除
- 实现多线程 并发 执行
package mainimport "fmt"func helloGoroutine() {for i := 0; i < 100; i++ {fmt.Println("hello world", i)}
}func main() {/*Go Goroutine, go语言中的协程,实现并发。- 关键字 go- 初始大小 4k,随着程序执行自动增长和删除- 实现多线程 并发 执行*/// 使用 go 实现协程go helloGoroutine()for i := 0; i < 100; i++ {fmt.Println("main ", i)}
}
runtime包
package mainimport ("fmt""runtime""time"
)func goSchedFunc() {go func() {for i := 0; i < 6; i++ {fmt.Println("goroutine", i)}}()runtime.Gosched()for i := 0; i < 6; i++ {fmt.Println("Main goroutine", i)}
}func runtimeGoExitFunc() {// 开启一个 goroutine 线程(协程,轻量级线程)go func() {fmt.Println("Start runtimeGoExitFunc")test()fmt.Println("End runtimeGoExitFunc")}()time.Sleep(time.Second * 3) // 当前函数睡三秒}func test() {defer fmt.Println("延时关闭test函数")runtime.Goexit() // 终止程序,即:结束当前线程(goroutine)fmt.Println("执行test函数")
}func main() {/*runtime 包- 获取系统的信息的工具包*/// 获取 goRoot 目录fmt.Println("GoRoot Path", runtime.GOROOT())// 获取操作系统fmt.Println("System", runtime.GOOS) // darwin// 获取CPU数量fmt.Println("NumCPU", runtime.NumCPU()) // 12// runtime.Gosched() 线程的礼让。让出时间片,即:让goroutine先执行goSchedFunc()// NumGoroutine返回当前存在的运行例程的数量。fmt.Println("NumGoroutine", runtime.NumGoroutine())// runtime.Goexit() 比肩 panic 终止程序runtimeGoExitFunc()//
}
多线程问题
- 临界资源安全问题。多线程调用共享变量
- 案例:售票问题
package mainimport ("fmt""time"
)func multithreadedSharedVariableMethods() {shareVariable := 1go func() {shareVariable = 2fmt.Println("GoRoutine shareVariable:", shareVariable)}()shareVariable = 3time.Sleep(1 * time.Second)fmt.Println("main shareVariable:", shareVariable)}
func main() {/*go 中 多线程的问题- 临界资源安全问题。多线程调用共享变量- 案例:售票问题-*/// 案例1。多线程共享变量multithreadedSharedVariableMethods()}
sync 同步锁
- 锁机制处理多线程抢占资源的问题
- 某个时间段内,只允许一个 goroutine访问共享数据。当goroutine访问完毕,释放锁后,其他goroutine才能访问
- 不要以共享内存的方式去通信,而是以通信方式去共享内存
- 不推荐使用 锁机制。 go语言中! 其他语言基本上都是以锁的方式处理
- go 中鼓励通过 channel 来解决 共享问题
package mainimport ("fmt""sync""time"
)// SmLock 同步锁【互斥锁】
var SmLock sync.Mutex// Swg 同步等待组。处理子协程执行完成
var Swg sync.WaitGroup// TickerNums 定义全局 票的数量
var TickerNums = 10func saleTicketFunc(ticketSeller string) {// 卖票函数for {if TickerNums > 0 {fmt.Println("获取票总量:", TickerNums)TickerNums--fmt.Println("售票员:", ticketSeller, "卖出1张票", "剩余票的量:", TickerNums)} else {fmt.Println("票卖完了!")break}}
}func saleTicketMainFunc() {// 卖票主函数go saleTicketFunc("张三")go saleTicketFunc("李四")go saleTicketFunc("王五")go saleTicketFunc("赵六")time.Sleep(3 * time.Second)
}func saleTicketMutexWaitGroupFunc(ticketSeller string) {// 卖票函数for {// 增加锁机制,锁住共享资源SmLock.Lock() // 上锁if TickerNums > 0 {fmt.Println("获取票总量:", TickerNums)TickerNums--fmt.Println("售票员:", ticketSeller, "卖出1张票", "剩余票的量:", TickerNums)} else {SmLock.Unlock() // 释放锁,否则进入锁死。fmt.Println("票卖完了!")break}SmLock.Unlock() // 释放锁}
}
func saleTicketMutexWaitGroupMainFunc() {// 增加售票互斥锁,增加上同步等待组。 卖票主函数Swg.Add(4)go saleTicketMutexFunc("张三")go saleTicketMutexFunc("李四")go saleTicketMutexFunc("王五")go saleTicketMutexFunc("赵六")Swg.Wait() // 等待全部协程处理完问题
}func saleTicketMutexFunc(ticketSeller string) {// defer 延时关闭 同步等待组defer Swg.Done()// 卖票函数for {// 增加锁机制,锁住共享资源SmLock.Lock() // 上锁if TickerNums > 0 {fmt.Println("获取票总量:", TickerNums)TickerNums--fmt.Println("售票员:", ticketSeller, "卖出1张票", "剩余票的量:", TickerNums)} else {SmLock.Unlock() // 释放锁,否则进入锁死。fmt.Println("票卖完了!")break}SmLock.Unlock() // 释放锁}
}
func saleTicketMutexMainFunc() {// 增加售票互斥锁。 卖票主函数go saleTicketMutexFunc("张三")go saleTicketMutexFunc("李四")go saleTicketMutexFunc("王五")go saleTicketMutexFunc("赵六")time.Sleep(3 * time.Second)
}func main() {/*sync 包。 锁机制处理多线程抢占资源的问题- 某个时间段内,只允许一个 goroutine访问共享数据。当goroutine访问完毕,释放锁后,其他goroutine才能访问- 不要以共享内存的方式去通信,而是以通信方式去共享内存- 不推荐使用 锁机制。 go语言中! 其他语言基本上都是以锁的方式处理- go 中鼓励通过 channel 来解决 共享问题-*/// 普通卖票。问题:共享资源抢占,sleep处理协程等待执行完成saleTicketMainFunc()// 进阶卖票。处理:解决共享资源抢占问题。 问题:sleep处理协程等待执行完成saleTicketMutexMainFunc()// 高阶卖票。处理:解决共享资源抢占问题,解决协程等待执行完成问题saleTicketMutexWaitGroupMainFunc()}
sync.WaitGroup 同步等待组
package mainimport ("fmt""runtime""sync"
)// SwgTest 定义 同步等待组
var SwgTest sync.WaitGroupfunc test1() {defer SwgTest.Done()for i := 0; i < 10; i++ {fmt.Println("T1", i)}
}
func test2() {for i := 0; i < 10; i++ {fmt.Println("T2", i)}SwgTest.Done()
}func main() {// 同步等待组。处理 goroutine 的等待问题SwgTest.Add(2) // 设定 线程 数量go test1()runtime.Gosched() // 下面的线程让出资源!go test2()// 垃圾处理: time.Sleep(time.Second * 3)//time.Sleep(time.Second * 1)// 优秀的处理: 同步等待组等待执行完成SwgTest.Wait()}
sync 的 锁 Lock + WaitGroup 同步等待组
package mainimport ("fmt""sync"
)// TickerNums2 定义全局 票的数量
var TickerNums2 = 10// SmLock2 同步锁【互斥锁】
var SmLock2 sync.Mutex// Swg2 同步等待组。处理子协程执行完成
var Swg2 sync.WaitGroupfunc saleTicketMutexFunc2(ticketSeller string) {// defer 延时关闭 同步等待组defer Swg2.Done()// 卖票函数for {// 增加锁机制,锁住共享资源SmLock2.Lock() // 上锁if TickerNums2 > 0 {fmt.Println("获取票总量:", TickerNums2)TickerNums2--fmt.Println("售票员:", ticketSeller, "卖出1张票", "剩余票的量:", TickerNums2)} else {SmLock2.Unlock() // 释放锁,否则进入锁死。fmt.Println("票卖完了!")break}SmLock2.Unlock() // 释放锁}
}
func saleTicketMutexWaitGroupMainFunc2() {// 增加售票互斥锁,增加上同步等待组。 卖票主函数Swg2.Add(4)go saleTicketMutexFunc2("张三")go saleTicketMutexFunc2("李四")go saleTicketMutexFunc2("王五")go saleTicketMutexFunc2("赵六")Swg2.Wait() // 等待全部协程处理完问题
}
func main() {// 高阶卖票。处理:解决共享资源抢占问题,解决协程等待执行完成问题saleTicketMutexWaitGroupMainFunc2()
}