go~协程阻塞分析

错误示例

go 复制代码
type chanData struct {
	result string
	error  error
}

func Biz1() {
	t := time.NewTimer(time.Second * 10)
	ctx := context.Background()

	ch := make(chan chanData)
	go doChan(ctx, ch)

	fmt.Println("Biz1 begin")
	for {
		select {
		case <-t.C:
			fmt.Println("Biz1 to time")
			return
		case data := <-ch:
			fmt.Println("Biz1 data", jsonx.ToString(data.result), "Biz1 err", data.error.Error())
			return
		}
	}
}

type RecoverHook func()

func Recover(ctx context.Context, method string, hooks ...RecoverHook) {
	if err := recover(); err != nil {
		const size = 64 << 10
		buf := make([]byte, size)
		buf = buf[:runtime.Stack(buf, false)]

		fmt.Printf("panic err: %v\n%v\n end!!!\n", err, string(buf))
		for _, hook := range hooks {
			hook()
		}
	}
}

func doChan(ctx context.Context, ch chan chanData) {
	fmt.Println("doChan begin")
	defer Recover(ctx, "doChan", func() {
		fmt.Println("Recover chan before")
		ch <- chanData{error: errors.New("panic happened")}
		fmt.Println("Recover chan after")
	})
	for i := 0; i < 12; i++ {
		fmt.Printf("doChan i:%v\n", i)
		time.Sleep(time.Second * 1)
	}
	panic("doChan panic")
	fmt.Println("doChan end")
}

func TestDemo111(t *testing.T) {
	f, err := os.Create("trace.out")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	err = trace.Start(f)
	if err != nil {
		panic(err)
	}
	defer trace.Stop()

	go Biz1()
	for i := 0; i < 20; i++ {
		fmt.Printf("Biz i:%v\n", i)
		time.Sleep(time.Second * 1)
	}
}

协程被阻塞8秒

正确示例

go 复制代码
type chanData struct {
	result string
	error  error
}

type ChanDataWapper struct {
	ch     chan chanData
	mu     *sync.Mutex
	closed bool
}

func NewChanInfo() *ChanDataWapper {
	return &ChanDataWapper{
		ch:     make(chan chanData),
		mu:     &sync.Mutex{},
		closed: false,
	}
}

func Biz1() {
	t := time.NewTimer(time.Second * 10)
	ctx := context.Background()

	dataChanWappter := NewChanInfo()
	defer func() {
		fmt.Println("Biz1 before close")
		dataChanWappter.mu.Lock()
		dataChanWappter.closed = true
		dataChanWappter.mu.Unlock()
		fmt.Println("Biz1 after close")
	}()

	go doChan(ctx, dataChanWappter)

	fmt.Println("Biz1 begin")
	for {
		select {
		case <-t.C:
			fmt.Println("Biz1 to time")
			return
		case data := <-dataChanWappter.ch:
			fmt.Println("Biz1 data", jsonx.ToString(data.result), "Biz1 err", data.error.Error())
			return
		}
	}
}

type RecoverHook func()

func Recover(ctx context.Context, method string, hooks ...RecoverHook) {
	if err := recover(); err != nil {
		const size = 64 << 10
		buf := make([]byte, size)
		buf = buf[:runtime.Stack(buf, false)]

		fmt.Printf("panic err: %v\n%v\n end!!!\n", err, string(buf))
		for _, hook := range hooks {
			hook()
		}
	}
}

func doChan(ctx context.Context, cw *ChanDataWapper) {
	fmt.Println("doChan begin")
	defer Recover(ctx, "doChan", func() {
		cw.mu.Lock()
		if !cw.closed {
			fmt.Println("Recover chan before")
			cw.ch <- chanData{error: errors.New("panic happened")}
			fmt.Println("Recover chan after")
		} else {
			fmt.Println("Recover chan closed")
		}
		cw.mu.Unlock()
	})
	for i := 0; i < 12; i++ {
		fmt.Printf("doChan i:%v\n", i)
		time.Sleep(time.Second * 1)
	}
	panic("doChan panic")
	fmt.Println("doChan end")
}

func TestDemo111(t *testing.T) {
	f, err := os.Create("trace.out")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	err = trace.Start(f)
	if err != nil {
		panic(err)
	}
	defer trace.Stop()

	go Biz1()
	for i := 0; i < 20; i++ {
		fmt.Printf("Biz i:%v\n", i)
		time.Sleep(time.Second * 1)
	}
}

go tool trace trace.out

相关推荐
Cuit小唐1 分钟前
C++好用的打印日志类
开发语言·c++·算法
code_shenbing18 分钟前
C#扩展方法与Lambda表达式基本用法
开发语言·c#·lambda表达式·扩展方法
江湖行骗老中医32 分钟前
js闭包概念和使用
开发语言·javascript·ecmascript
FAREWELL0007535 分钟前
C#进阶学习(十七)PriorityQueue<TElement, TPriority>优先级队列的介绍
开发语言·学习·c#·优先级队列
weixin_4565881541 分钟前
【Spring Boot 注解】@ConfigurationProperties
spring boot·后端
海绵宝宝的月光宝盒1 小时前
[stm32] 4-1 USART(1)
c语言·开发语言·笔记·stm32·单片机
九班长1 小时前
JMeter WebSocket 压测详细步骤(支持 ws+proto 协议)
开发语言·python·网络协议·jmeter·golang
IsPrisoner1 小时前
GoLang基础
笔记·golang
小安同学iter2 小时前
苍穹外卖心得体会
java·开发语言·spring boot·servlet·intellij-idea·mybatis
chunfeng—2 小时前
纯C协程框架NtyCo
linux·c++·后端·协程·ntyco