golang中各种状态下channel(管道)的读、写、close操作

一、简介

golang中各种状态下channel(管道)的读、写、close操作

二、结论

channel状态 close
close 零值 panic panic
nil 永久阻塞(deadlock) 永久阻塞(deadlock) panic
buffer满 正常 永久阻塞(deadlock) 正常
buffer空 永久阻塞(deadlock) 正常 正常

三、验证

创建两个go文件
管道状态文件:chan_state.go
测试文件:chan_state_test.go

命令行执行

go test -v

结果见第四部分

chan_state.go

package channel

import "fmt"

type BaseChan interface {
	Read()
	Write()
	Close()
}

type BasicActionChan struct {
	ch chan int
}

func (ch *BasicActionChan) Read() {
	value := <-ch.ch
	fmt.Println("read success", value)
}

func (ch *BasicActionChan) Write() {
	ch.ch <- 1
	fmt.Println("write success")
}

func (ch *BasicActionChan) Close() {
	close(ch.ch)
}

type CloseChan struct {
	BasicActionChan
}

func NewCloseChan() BaseChan {
	ch := &CloseChan{BasicActionChan{ch: make(chan int)}}
	close(ch.ch)
	return ch
}

type NilChan struct {
	BasicActionChan
}

func NewNilChan() BaseChan {
	ch := &NilChan{BasicActionChan{ch: nil}}
	return ch
}

type FullBufferChan struct {
	BasicActionChan
}

func NewFullBufferChan() BaseChan {
	ch := &FullBufferChan{BasicActionChan{ch: make(chan int, 1)}}
	ch.ch <- 1
	return ch
}

type EmptyBufferChan struct {
	BasicActionChan
}

func NewEmptyBufferChan() BaseChan {
	ch := &EmptyBufferChan{BasicActionChan{ch: make(chan int, 1)}}
	return ch
}

chan_state_test.go

package channel

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

type Case struct {
	Name   string
	Ch     BaseChan
	Action func(baseChan BaseChan)
}

func helper(t *testing.T, c *Case) {
	t.Helper()
	t.Run(c.Name, func(tt *testing.T) {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
		defer cancel()
		done := make(chan struct{})
		panicCh := make(chan struct{})
		go func() {
			defer func() {
				if err := recover(); err != nil {
					fmt.Println("panic ", err)
					panicCh <- struct{}{}
				}
			}()
			c.Action(c.Ch)
			done <- struct{}{}
		}()
		select {
		case <-ctx.Done():
			fmt.Println("timeout ")
		case <-panicCh:

		case <-done:
			fmt.Println("success")
		}
	})
}

func TestNewCloseChan(t *testing.T) {
	helper(t, &Case{Name: "close chan read", Ch: NewCloseChan(), Action: func(baseChan BaseChan) {
		baseChan.Read()
	}})

	helper(t, &Case{Name: "close chan write", Ch: NewCloseChan(), Action: func(baseChan BaseChan) {
		baseChan.Write()
	}})

	helper(t, &Case{Name: "close chan close", Ch: NewCloseChan(), Action: func(baseChan BaseChan) {
		baseChan.Close()
	}})
}

func TestNewNilChan(t *testing.T) {
	helper(t, &Case{Name: "nil chan read", Ch: NewNilChan(), Action: func(baseChan BaseChan) {
		baseChan.Read()
	}})

	helper(t, &Case{Name: "nil chan write", Ch: NewNilChan(), Action: func(baseChan BaseChan) {
		baseChan.Write()
	}})

	helper(t, &Case{Name: "nil chan close", Ch: NewNilChan(), Action: func(baseChan BaseChan) {
		baseChan.Close()
	}})
}

func TestNewFullBufferChan(t *testing.T) {
	helper(t, &Case{Name: "full chan read", Ch: NewFullBufferChan(), Action: func(baseChan BaseChan) {
		baseChan.Read()
	}})

	helper(t, &Case{Name: "full chan write", Ch: NewFullBufferChan(), Action: func(baseChan BaseChan) {
		baseChan.Write()
	}})

	helper(t, &Case{Name: "full chan close", Ch: NewFullBufferChan(), Action: func(baseChan BaseChan) {
		baseChan.Close()
	}})
}

func TestNewEmptyBufferChan(t *testing.T) {
	helper(t, &Case{Name: "empty chan read", Ch: NewEmptyBufferChan(), Action: func(baseChan BaseChan) {
		baseChan.Read()
	}})

	helper(t, &Case{Name: "empty chan write", Ch: NewEmptyBufferChan(), Action: func(baseChan BaseChan) {
		baseChan.Write()
	}})

	helper(t, &Case{Name: "empty chan close", Ch: NewEmptyBufferChan(), Action: func(baseChan BaseChan) {
		baseChan.Close()
	}})
}

四、结果

posted @   genec  阅读(322)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示