go modules
同目录下,不同的go文件不能有不同的package,只能有一个main
包的引用
使用WaitGroup控制协程控制
互斥锁,使用sync.Mutex 的lock和unlock来实现互斥操作
package main
import (
"fmt"
"sync"
)
var total int
var wg sync.WaitGroup
var lock sync.Mutex
// 互斥锁
func add() {
defer wg.Done()
for i :=0; i<1000000; i++ {
lock.Lock()
total += 1
lock.Unlock()
}
}
func sub() {
defer wg.Done()
for i := 0; i<1000000; i++{
lock.Lock()
total -= 1
lock.Unlock()
}
}
func main() {
wg.Add(2) // 两个协程
go add()
go sub()
wg.Wait()
fmt.Println(total)
}
同步问题,使用sync.RWMutex的 来实现读写锁
package main
import (
"fmt"
"sync"
"time"
)
var total int
var wg sync.WaitGroup
var lock sync.Mutex
var rwLock sync.RWMutex
// 互斥锁
func add() {
defer wg.Done()
for i :=0; i<1000000; i++ {
lock.Lock()
total += 1
lock.Unlock()
}
}
func sub() {
defer wg.Done()
for i := 0; i<1000000; i++{
lock.Lock()
total -= 1
lock.Unlock()
}
}
func read() {
defer wg.Done()
rwLock.RLock()
fmt.Println("开始读数据")
time.Sleep(time.Second)
fmt.Println("读取成功")
rwLock.RUnlock()
}
func write() {
defer wg.Done()
rwLock.Lock()
fmt.Println("开始修改数据")
time.Sleep(time.Second*10)
fmt.Println("修改成功")
rwLock.Unlock()
}
func main() {
wg.Add(5) // 两个协程
for i:=0; i<5;i++ {
go read()
}
wg.Wait()
fmt.Println(total)
}
channel机制
使用range遍历channel
func consumer(queue chan int) {
defer wg.Done()
for{
data, ok := <- queue
if !ok{
break
}
fmt.Println(data)
time.Sleep(time.Second)
}
}
func main() {
var msg chan int
msg = make(chan int, 1)
msg <- 1
wg.Add(1)
go consumer(msg)
msg <- 2
close(msg)
wg.Wait()
}
使用 chan<-和chan<- 设置为单向的管道
使用channel容易出现deallock是因为:msg <- 1是放数据进去,放进去需要获取锁,但是没有取数据,故会出现死锁
故:
select
timeout := make(chan bool, 2)
go func() {
//该goroutine 如果执行时间超过了5s,那么就报告给主的goroutine
time.Sleep(time.Second*5)
timeout <- true
}()
timeout2 := make(chan bool, 2)
go func() {
//该goroutine 如果执行时间超过了5s,那么就报告给主的goroutine
time.Sleep(time.Second*1)
timeout2 <- true
}()
select {
case <-timeout:
fmt.Println("超时了")
case <-timeout2:
fmt.Println("超时了")
default:
fmt.Println("继续下一次")
}
需求:取消一个定时监控cpu信息的协程
可以由三种方法来完成:①,全局变量,②:使用select 的 case 和default来完成。③:使用context机制,代码如下:
// context
func cpuInfo(ctx context.Context) {
defer wg.Done()
for {
select {
case <- ctx.Done():
fmt.Println("监控退出")
return
default:
time.Sleep(time.Second)
fmt.Println("获取cpu信息成功")
}
}
}
func main() {
wg.Add(1)
ctx, cancel := context.WithCancel(context.Background())
go cpuInfo(ctx)
time.Sleep(time.Second * 6)
cancel()
wg.Wait()
fmt.Println("信息监控完成")
}
context的特性:父context结束,子context也结束,多个context一并结束
golang提供的context有三种:context.WithDeadline() context.WithTimeout() context.WithValue()