Golang并发模型:并发协程的优雅退出

goroutine的退出机制,不能通过某种手段强制关闭,只能等goroutine主动退出。

常用三种方式:

一、 通道 有 chan, for range、 for select

  1. for-range, 当无缓存通道关闭时,for-range 自动退出。 需要close(chan) , 否则会死锁。

  2. 使用 select  ok 退出

  •         for-select也是使用频率很高的结构,select提供了多路复用的能力,所以for-select可以让函数具有持续多路处理多个channel的能力。但select没有感知channel的关闭,这引出了2个问题:
  1. 继续在关闭的通道上读,会读到通道传输数据类型的零值,如果是指针类型,读到nil,继续处理还会产生nil。

  2. 继续在关闭的通道上写,将会panic。

package main

import (
	"fmt"
	"time"
)

func main() {
	done := make(chan bool)
	go func() {
		for {
			select {
			case <-done:
				fmt.Println("退出协程01")
				return
			default:
				fmt.Println("监控01 ....")
				time.Sleep(1 * time.Second)
			}
		}
	}()

	go func() {
		for res := range done {
			fmt.Println(res) //没有消息则是阻塞状态 //chan 关闭则for循环结束
		}
		fmt.Println("退出监控03")
	}()
	go func() {
		for {
			select {
			case <-done:
				fmt.Println("退出协程02")
				return
			default:
				fmt.Println("监控02.。。")
				time.Sleep(1 * time.Second)
			}

		}
	}()

	time.Sleep(3 * time.Second)
	close(done)
	time.Sleep(5 * time.Second)
	fmt.Println("退出程序")

}

二、 context

初识 Context包

一个用于手动控制 goroutine 退出或者结束

获取 context上下文两种方式

ctx := context.Background() //这只能用于高等级(在 main 或顶级请求处理中)。这能用于派生我们稍后谈及的其他 context

ctx := context.TODO() // 也只能用于高等级或当您不确定使用什么 context,或函数以后会更新以便接收一个 context

使用 context.WithTimeout,主动调用 cancel()方法,可以在时间超时之前退出 goroutine

使用 context.WithCanel()方法,根据外部条件手动调用 cancel()方法退出

使用 context.WithDeadLine() ,在指定的时间退出 goroutine

使用 context.WithValue()传值,在所有的context树中都能获取到该值,如果设置相同的key 则覆盖该值

Golang并发模型:并发协程的优雅退出_第1张图片

 

package main

import (
    "context"
    "fmt"
    "time"
)

func exit04() {
    ctx, cancel := context.WithCancel(context.Background())
    go func() {
        for {
            select {
            case <-ctx.Done():
                fmt.Println("退出协程")
                return
            default:
                fmt.Println("监控01")
                time.Sleep(1 * time.Second)

            }

        }

    }()

    time.Sleep(5 * time.Second)
    cancel()
    time.Sleep(2 * time.Second)
    fmt.Println("退出程序")

}
func main() {
    exit04()
}

Golang并发模型:并发协程的优雅退出_第2张图片

 Golang并发模型:并发协程的优雅退出_第3张图片

 

你可能感兴趣的:(golang,开发语言,后端)