Go Chan 实用写法


写法核心在有注释的部分

读管道

判断读管道中是否还有数据

注意,此写法不能用于判断管道是否关闭

package main

import (
	"fmt"
)

func main() {
	ch := make(chan string, 10)
	ch <- "hello"
	ch <- "world"
    // 判断数据状态
	if val, open := <-ch; !open {
		fmt.Println("channel is closed")
	} else {
		fmt.Println(val, open)
	}
	close(ch)
	if val, open := <-ch; !open {
		fmt.Println("channel is closed")
	} else {
		fmt.Println(val, open)
	}
}

取出管道中的所有数据,直到管道关闭

package main

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

func main() {
	ch := make(chan string)
	ctx, cancel := context.WithCancel(context.Background())

	go func(cancel func()) {
		time.Sleep(5 * time.Second)
		cancel()
		close(ch)
	}(cancel)

	go func(ctx context.Context) {
		num := 0
		for {
			select {
			case <-ctx.Done():
				fmt.Println("done")
				return
			default:
				ch <- fmt.Sprintf("hello %d", num)
				num++
				time.Sleep(1 * time.Second)
			}

		}
	}(ctx)
	
    // 	for val := range ch 会取出 ch 中的所有数据,其退出条件是,ch 被关闭且 ch 中的数据被全部取出 
	for val := range ch {
		fmt.Println(val)
	}
	time.Sleep(10 * time.Second)
}

写管道

使用 content 来管理状态

package main

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

func main() {
	ch := make(chan string)
	ctx, cancel := context.WithCancel(context.Background())

	go func(cancel func()) {
		time.Sleep(5 * time.Second)
        // 关闭管道之前先关闭 content
		cancel()
		close(ch)
	}(cancel)

	go func(ctx context.Context) {
		num := 0
		for {
            //此处来去控制写管道
			select {
			case <-ctx.Done():
				fmt.Println("done")
				return
			default:
				ch <- fmt.Sprintf("hello %d", num)
				num++
				time.Sleep(1 * time.Second)
			}

		}
	}(ctx)
	
	for val := range ch {
		fmt.Println(val)
	}
	time.Sleep(10 * time.Second)
}

panic+recover

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan string)
	go func() {
		time.Sleep(5 * time.Second)
		close(ch)
	}()
	go func() {
        // 让它 panic 后恢复,借此来判断管道关闭
    	// 此写法需要单独抽象成一个函数,其中最好不可能有其他的 panic
		defer func() {
			if err := recover(); err != nil {
				fmt.Println("recover", err)
			}
		}()
		num := 0
		for {
			ch <- fmt.Sprintf("hello %d", num)
			num++
			time.Sleep(1 * time.Second)
		}
	}()
	for val := range ch {
		fmt.Println(val)
	}
	time.Sleep(10 * time.Second)
}

如果本文帮助到了你,帮我点个广告可以咩(o′┏▽┓`o)


文章作者: Anubis
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Anubis !
评论
  目录