12 go 并发编程二
1.select的用法。
func g1(ch1 chan struct{}) { time.Sleep(3 * time.Second) ch1 <- struct{}{} } func g2(ch2 chan struct{}) { time.Sleep(4 * time.Second) ch2 <- struct{}{} } func main() { g1Channel := make(chan struct{}) g2Channel := make(chan struct{}) go g1(g1Channel) go g2(g2Channel) // 我要监控多个channel任何一个有值都知道 //1. 某一个分支就绪了就执行该分支 //2. 如果两个都就绪了 先执行哪个 随机的 目的是防止饥饿 防止一直只能拿到一个固定的锁 tm := time.NewTimer(time.Second * 5) select { case <-g1Channel: fmt.Println("g1 done") case <-g2Channel: fmt.Println("g2 done") case <-tm.C: fmt.Println("default") return } }
var wg sync.WaitGroup var stop bool func cpuInfo() { defer wg.Done() for { if stop { break } time.Sleep(time.Second) fmt.Println("cpu 监控") } } func main() { wg.Add(1) go cpuInfo() time.Sleep(time.Second * 3) stop = true wg.Wait() }
var wg sync.WaitGroup var stop = make(chan struct{}) func cpuInfo() { defer wg.Done() for { select { case <-stop: fmt.Println("退出cpu监控") return default: time.Sleep(time.Second) fmt.Println("cpu 监控") } } } func main() { wg.Add(1) go cpuInfo() time.Sleep(time.Second * 3) stop <- struct{}{} wg.Wait() }
2. contex的用法。
在Go语言中,context包提供了一种在多个goroutine之间传递请求范围的值、取消信号以及截止时间的方式。context.Context接口是Go语言中用于控制goroutine生命周期和传递请求范围的数据的。 context.Background()函数返回一个非关联到任何取消信号的空context。这个空context可以用来作为其他context的父context,它永远不会被取消,也没有值可以被传递。 当你看到代码: go ctx1, _ := context.WithTimeout(context.Background(), time.Second*6) 这里的context.Background()创建了一个空的context,然后context.WithTimeout函数被用来创建一个新的context,这个新的context有一个截止时间。在这个例子中,截止时间被设置为6秒。 context.WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)函数接受两个参数: parent:父context,用于创建一个新的context。在这里,父context是一个空的context,由context.Background()返回。 timeout:超时时间,表示新创建的context将在指定的时间后自动取消。 函数返回两个值: 一个新的Context,它在指定的超时时间后会被取消。 一个CancelFunc,可以用来手动取消这个context。
package main import ( "context" "fmt" "sync" "time" ) var wg sync.WaitGroup var stop = make(chan struct{}) func cpuInfo(ctx context.Context) { defer wg.Done() for { select { case <-ctx.Done(): fmt.Println("退出cpu监控") return default: time.Sleep(time.Second) fmt.Println("cpu 监控") } } } // context解决 父的线程给子的线程发送一些消息
// context 提供了三种函数WithCancel WithTimeout WithValue
func main() { wg.Add(1) ctx, cancel := context.WithCancel(context.Background()) go cpuInfo(ctx) time.Sleep(time.Second * 3) cancel() wg.Wait() }
主动取消
var wg sync.WaitGroup var stop = make(chan struct{}) func cpuInfo(ctx context.Context) { defer wg.Done() for { select { case <-ctx.Done(): fmt.Println("退出cpu监控") return default: time.Sleep(time.Second) fmt.Println("cpu 监控") } } } // context解决 父的线程给子的线程发送一些消息 func main() { wg.Add(1) //context 提供了三种函数WithCancel WithTimeout WithValue // 如果你的goroutine、函数 希望被控制。超时 传值的时候不希望影响原来接口信息的时候 // 函数第一个值尽量加上context ctx, cancel := context.WithCancel(context.Background()) ctx1, _ := context.WithCancel(ctx) go cpuInfo(ctx1) time.Sleep(time.Second * 3) cancel() wg.Wait() }
context.WithTimeout 超时取消
func main() { wg.Add(1) //context 提供了三种函数WithCancel WithTimeout WithValue // 如果你的goroutine、函数 希望被控制。超时 传值的时候不希望影响原来接口信息的时候 // 函数第一个值尽量加上context // 主动超时取消 ctx1, _ := context.WithTimeout(context.Background(), time.Second*6) go cpuInfo(ctx1) wg.Wait() }
context.WithValue 传值
package main import ( "context" "fmt" "sync" "time" ) var wg sync.WaitGroup //var stop = make(chan struct{}) func cpuInfo(ctx context.Context) { v := ctx.Value("requestId") fmt.Printf("%s \n\r", v) defer wg.Done() for { select { case <-ctx.Done(): fmt.Println("退出cpu监控") return default: time.Sleep(time.Second) fmt.Println("cpu 监控") } } } // context解决 父的线程给子的线程发送一些消息 func main() { wg.Add(1) //context 提供了三种函数WithCancel WithTimeout WithValue // 如果你的goroutine、函数 希望被控制。超时 传值的时候不希望影响原来接口信息的时候 // 函数第一个值尽量加上context // 主动超时取消 ctx1, _ := context.WithTimeout(context.Background(), time.Second*6) ctx2 := context.WithValue(ctx1, "requestId", "5748ghjgfj34rf") go cpuInfo(ctx2) // context.WithDeadline() 在指定时间取消 在12:00点整取消 wg.Wait() }
时来天地皆同力,运去英雄不自由