闭包,使用不当,会出问题

        同事在初始化redis配置的时候,给Dial函数赋值时用了闭包,导致程序上线后,数据怎么都加载不到redis中去,排查了半个多小时,总算找到了罪魁祸首。虽然自己之前对闭包也算了解,但是看到他的那段代码的时候,乍一看竟也没发现出问题来,所以决定写篇文章加深印象,避免自己以后也犯类似的问题。

        先上代码:

func InitRedis() error {
    GRedis = make(map[string]*Cache)
    for _, gConfig := range config.GConfigs.RedisList {  //遍历配置文件,redisList存放了各个redis服务器的ip、端口号以及密码等信息。
        c := new(Cache)
        c.pool = &redis.Pool{
            MaxIdle:     gConfig.Conf.MaxConn,
            MaxActive:   gConfig.Conf.MaxConn,
            IdleTimeout: 240 * time.Second,
            Dial: func() (redis.Conn, error) {   //连接实例的Dial函数,这里用了闭包,其中gConfig为自由变量
                c, err := redis.Dial("tcp", gConfig.Conf.IP+":"+gConfig.Conf.Port, redis.DialConnectTimeout(60*time.Second), redis.DialReadTimeout(60*time.Second), redis.DialWriteTimeout(60*time.Second))  
                if err != nil { 
                    return nil, err
                }
                if gConfig.Conf.Password != "" {
                    if _, err := c.Do("AUTH", gConfig.Conf.Password); err != nil {
                        c.Close()
                        return nil, err
                    }
                }
                return c, err
            },
        }

        c.prefix = gConfig.Conf.Prefix
        GRedis[gConfig.Name] = c
    }

    return nil
}

        上述代码已对关键部分(涉及公司机密)进行了删除和处理。
        乍一看是不是很难发现问题到底出在哪,我们当时碰到的问题是,数据没有从db加载到redis服务器1中,经过排查,发现db的数据全加载到了redis服务器3中了。恰巧redis服务器3是配置文件中的最后一个,也就是for循环中遍历的最后一个。进而我们发现Dial函数对应的闭包函数里引用了gConfig这个自由变量。
        这会导致什么问题呢?我们先来温习一下闭包的特性:有自由变量的匿名函数是闭包,闭包的特性,就是内层函数引用了外层函数中的变量,注意是引用哦。
        所以,这会导致redis连接池中每个连接去做Dial的时候,拿到的都是for循环中最后一个gConfig,即连接的都是redis服务器3,去redis服务器1里面拿数据当然就什么都拿不到了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值