了解计算机原理
- 进程:计算机资源分配单位
- 线程:cpu处理单位
- 协程:以 特殊机制或者函数实现高并发,又称 轻量级线程
了解Goroutine
- Go Goroutine, go语言中的协程,实现并发。
- 关键字 go
- 初始大小 4k,随着程序执行自动增长和删除
- 实现多线程 并发 执行
package main
import "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 main
import (
"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 main
import (
"fmt"
"time"
)
func multithreadedSharedVariableMethods() {
shareVariable := 1
go func() {
shareVariable = 2
fmt.Println("GoRoutine shareVariable:", shareVariable)
}()
shareVariable = 3
time.Sleep(1 * time.Second)
fmt.Println("main shareVariable:", shareVariable)
}
func main() {
/*
go 中 多线程的问题
- 临界资源安全问题。多线程调用共享变量
- 案例:售票问题
-
*/
// 案例1。多线程共享变量
multithreadedSharedVariableMethods()
}
sync 同步锁
- 锁机制处理多线程抢占资源的问题
- 某个时间段内,只允许一个 goroutine访问共享数据。当goroutine访问完毕,释放锁后,其他goroutine才能访问
- 不要以共享内存的方式去通信,而是以通信方式去共享内存
- 不推荐使用 锁机制。 go语言中! 其他语言基本上都是以锁的方式处理
- go 中鼓励通过 channel 来解决 共享问题
package main
import (
"fmt"
"sync"
"time"
)
// SmLock 同步锁【互斥锁】
var SmLock sync.Mutex
// Swg 同步等待组。处理子协程执行完成
var Swg sync.WaitGroup
// TickerNums 定义全局 票的数量
var TickerNums = 10
func 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 main
import (
"fmt"
"runtime"
"sync"
)
// SwgTest 定义 同步等待组
var SwgTest sync.WaitGroup
func 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 main
import (
"fmt"
"sync"
)
// TickerNums2 定义全局 票的数量
var TickerNums2 = 10
// SmLock2 同步锁【互斥锁】
var SmLock2 sync.Mutex
// Swg2 同步等待组。处理子协程执行完成
var Swg2 sync.WaitGroup
func 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()
}