go 常见问题总结

1、golang 使用json序列化报 NaN +Inf 解决方法

在使用JSON包或者无论是encoding下面的那个工具包,在序列化和反向序列化数据的时候,如果报NaN 或者Inf等字样,表示需要序列化的数据有问题。
NaN:代表不是一个数 Not a number。
Inf :代表阶码溢出,前面的加减符号代表高地位溢出,也就是小数点位后面无限大,使用不能很好的序列化。

解决办法:
NaN:使用fmt.Sprintf("%0.2f",浮点数) 输出一个字符串,判断字符串是否为“NaN”,如果是,给定一个初始值。
Inf :使用fmt.Sprintf("%0.2f",浮点数) 输出一个字符串的固定位的浮点数,再把这个浮点数转为float 即可 。

2、Golang利用select实现超时机制

在使用goroutine的时候,避免程序超时造成阻塞。(比如文件的读取)

解决办法:
可以使用select来设置超时

//新开一个协程
go func() {
	for {
		select {
		case num := <-ch: //如果有数据,下面打印。但是有可能ch一直没数据
			fmt.Println("num = ", num)
		case <-time.After(3 * time.Second): //上面的ch如果一直没数据会阻塞,那么select也会检测其他case条件,检测到后3秒超时
			fmt.Println("超时")
			quit <- true //写入
		}
	}

}() //别忘了()

3、map的线程安全使用

go中并发使用map时,因为map不是并发安全的,会报错:fatal error: concurrent map writes

避免、解决办法

  1. 尽量少定义全局map变量

  2. 如果必须定义全局map变量,可以加锁
    1. 优化1.可以采用cow策略,read不加锁,每次修改copy修改,再赋值
    2. 优化2.可以采用分片锁,减小锁的粒度

  3. 使用sync.Map
    主要方法:
    1. Store(key, value interface{}) — 说明: 存储一个设置的键值。
    2. LoadOrStore(key, value interface{}) (actual interface{}, loaded
    bool) — 说明: 返回键的现有值(如果存在),否则存储并返回给定的值,如果是读取则返回true,如果是存储返回false。
    3. Load(key interface{}) (value interface{}, ok bool) — 说明:读取存储在map中的值,如果没有值,则返回nil。OK的结果表示是否在map中找到值。
    4. Delete(key interface{}) — 说明: 删除键对应的值。
    5. Range(f func(key, value interface{}) bool) — 说明: 循环读取map中的值。

    参考:
    1、https://www.jianshu.com/p/2ef0566c75d9
    2、https://studygolang.com/articles/29582
    3、https://www.jianshu.com/p/1d45e31343d8

4、float64的四舍五入

由于受浮点数精度的影响

import (
    "math"
)

// Round 四舍五入,ROUND_HALF_UP 模式实现
// 返回将 val 根据指定精度 precision(十进制小数点后数字的数目)进行四舍五入的结果。precision 也可以是负数或零。
func Round(val float64, precision int) float64 {
    p := math.Pow10(precision)
    return math.Floor(val*p+0.5) / p
}

5、 for-select因定义空default导致CPU占用达到100%

var ch chan int
		for {
			select {
			case <-ch:
				return
			default:
			}
		}

对于select语句,每个case的IO事件都是阻塞的,监听IO事件是不会占用CPU至满的。
造成CPU占用的原因是这个空default,因为当case的条件不满足时,循环将会走default,然后执行下一个循环,这就造成了死循环,因此在使用for-select语句的时候不能定义空的default。
解决办法:
default里面使用:time.Sleep(),并且sleep时间结束之后做return处理。

6、Golang 数组 注意细节

  1. 数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化。
  2. var arr[]int,这个arr就是slice切片。
  3. 数组中的元素可以是任何数据类型,包括值类型和引用类型,但不能混用(不能int和float混用)
  4. 数组创建后,如果没有赋值,是有默认值的,数值类型默认是0;字符串类型默认"",bool类型默认false
  5. 使用数组的步骤:1.声明数组并开辟空间。2.给数组各个元素赋值。3.使用数组
  6. 数组的下标是从0开始的
  7. 数组下标必须在指定范围内使用,否则报panic,数组越界(var arr [5]int,则有效下标为0-4)
  8. Golang的数组属于值类型,在默认情况下是值传递,因此会进行拷贝, 数组间不会有影响
  9. 如果想在函数中修改数组的元素,可以使用引用传递修改(指针)

7、go 的 url 中的通配符 “:” 和 “*”

  1. 通配符以’:’(参数)或’*’(通配符)开头。
  2. 通配符名称不能包含:和*。
  3. 通配符不能没有有名称。

背景:
在反向代理的时候,有如下接口:

api/v1/test
api/v1/test/jiekou
api/v1/test666/jiekou
api/v1/test666/jiekou1

现希望前面4个接口转发到 6666 端口,api/v1/test666/jiekou 和 api/v1/test666/jiekou1 转发到 8888 端口.
解决办法:

[proxy-1]
ReqPrefix = "api/v1/:param/*path"
Target = 'http://172.66.0.8:6666'

[proxy-2]
ReqPrefix = "api/v1/:param"
Target = 'http://172.66.0.8:6666'

[proxy-3]
ReqPrefix = "api/v1/test666/*path"
Target = 'http://172.66.0.8:8888'
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值