Go学习笔记(四)

channel 关闭导致的问题

因为向关闭的channel 中传递数据导致 panic, 代码如下:

func GetToken(ctx context.Context) (t string, err error) {
	ctxTimeout, cancel := context.WithTimeout(context.TODO(), 500*time.Millisecond)
	defer cancel()

	var token string
	signal := make(chan struct{})
	defer close(signal)

	go func() {
		token, err = infsecc.GetToken(false)
		if err != nil {
			logs.CtxWarn(ctx, "get psm token error: %s", err.Error())
		}
		signal <- struct{}{}
	}()

	select {
	case <-ctxTimeout.Done():
		token = DefaultToken
		err = errors.New("get token timeout")
		logs.CtxWarn(ctx, "get token timeout")
	case <-signal:
	}

	if len(token) == 0 {
		logs.CtxWarn(ctx, "get token failed")
		token = DefaultToken
	}

	return token, err
}

经验教训如下:

  • channel 应该只能在发送端关闭;
  • channel 可以不关闭,由系统自动回收;
    代码修改如下:
func GetToken(ctx context.Context) (t string, err error) {
   ctxTimeout, cancel := context.WithTimeout(context.TODO(), 500*time.Millisecond)
   defer cancel()

   var token string
   signal := make(chan struct{})

   go func() {
   	token, err = infsecc.GetToken(false)
   	if err != nil {
   		logs.CtxWarn(ctx, "get psm token error: %s", err.Error())
   		return
   	}
   	signal <- struct{}{}
   }()

   select {
   case <-ctxTimeout.Done():
   	token = DefaultToken
   	err = errors.New("get token timeout")
   	logs.CtxWarn(ctx, "get token timeout")
   case <-signal:
   }

   if len(token) == 0 {
   	logs.CtxWarn(ctx, "get token failed")
   	token = DefaultToken
   }

   return token, err
}

值传递与引用传递

在这里插入图片描述
Go语言参数传递是传值还是传引用

list 与map 同样是引用拷贝,但二者还是有差别的;

package main

import "fmt"
import "unsafe"

func main() {
	fmt.Println("Hello, 世界")
	
	m := make(map[int]int,0)
	var t map[int]int
	t = m
	for i:=0; i< 10000; i++ {
		t[i] =  i
	}
	fmt.Println(len(t))
	fmt.Println(len(m))

	l1 := make([]int, 0, 4)
	l2 := l1
	for i := 0; i< 10000; i++ {
		l2 = append(l2, i)
	}
	fmt.Println(l2)
	fmt.Println(l1)
	
	// list 是一个结构体
	fmt.Println(unsafe.Sizeof(l1))
	fmt.Println(unsafe.Sizeof(l2))
	// map 是一个指针结构
	fmt.Println(unsafe.Sizeof(m))
	fmt.Println(unsafe.Sizeof(t))
}

编码过程中遭遇到的问题
func ImageHandlerCommon(data []byte) map[string]interface{} {
	......
	// metrics monitor
	defer util.HandleMonitor("image_app_load", tool.InterfaceToString(mainLog["app_id"]),
		tool.InterfaceToString(mainLog["app_version"]))
	......

这一句代码放在方法的最初, 发现最后执行的方法里面 :tool.InterfaceToString(mainLog[“app_version”]) 的值为空,发现是值传递导致的问题;
而后面把这一句代码放在方法的最后面,因为此时mainLog 已经处理完成,就没有空值的问题。

读写锁引入的问题

项目中对鉴权信息用一个LRU进行了缓存,LRU底层是go 源码库中包含的链表, 外部用读写锁控制访问;
写入LRU的时候,使用写锁;读取的时候,使用读锁,因为是一个LRU,读取的时候,如果在缓存,还会把Item放到链表头部;这里引入了一个潜在问题, 读取与写入偶然情况下,会同时操作底层的list, 导致读取的时候,获取的元素为空;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值