同理,如果函数的参数类型是slice,map或interface{}都会导致参数逃逸 。
匿名函数的调用也是一样的,它本质上也是一个函数变量 。有兴趣的可以自己测试一下 。
只要使用了Interface类型(不是interafce{}),那么赋值给它的变量一定会逃逸 。因为interfaceVariable.Method()先是间接的定位到它的实际值,再调用实际值的同名方法,执行时实际值作为参数传递给方法 。相当于interfaceVariable.Method.this = realValue
向 channel 中发送数据 , 本质上就是为 channel 内部的成员赋值 , 就像给一个 slice 中的某一项赋值一样 。所以chan *Type,chan map[Type]Type,chan []Type,chan interface{}类型都会导致发送到 channel 中的数据逃逸 。
这本来也是情理之中的,发送给 channel 的数据是要与其他函数分享的,为了保证发送过去的指针依然可用 , 只能使用堆分配 。
可变参数如func(arg ...string)实际与func(arg []string)是一样的,会增加一层访问路径 。这也是fmt.Sprintf总是会使参数逃逸的原因 。
例子非常多,这里不能一一列举,我们只需要记住分析方法就好 , 即,2 级或更多级的访问赋值会容易导致数据逃逸 。这里加上容易二字是因为随着语言的发展 , 相信这些问题会被慢慢解决,但现阶段,这个可以作为我们分析逃逸现象的依据 。
下面代码中包含 2 种很常规的写法,但他们却有着很大的性能差距,建议自己想下为什么 。
Benchmark 和 pprof 给出的结果:
熟悉堆栈概念可以让我们更容易看透 Go 程序的性能问题,并进行优化 。
多级间接赋值会导致 Go 编译器出现不必要的逃逸,在一些情况下可能我们只需要修改一下数据结构就会使性能有大幅提升 。这也是很多人不推荐在 Go 中使用指针的原因,因为它会增加一级访问路径,而map,slice,interface{}等类型是不可避免要用到的,为了减少不必要的逃逸,只能拿指针开刀了 。
大多数情况下,性能优化都会为程序带来一定的复杂度 。建议实际项目中还是怎么方便怎么写,功能完成后通过性能分析找到瓶颈所在,再对局部进行优化 。
Go语言实践模式 - 函数选项模式(Functional Options Pattern)大家好go语言函数内的变量自增,我是小白go语言函数内的变量自增 , 有点黑的那个白 。
最近遇到一个问题go语言函数内的变量自增,因为业务需求,需要对接第三方平台.
而三方平台提供的一些HTTP(S)接口都有统一的密钥生成规则要求.
为此我们封装go语言函数内的变量自增了一个独立的包 xxx-go-sdk 以便维护和对接使用.
其中核心的部分是自定义HTTP Client,如下:
一些平台会要求appKey/appSecret等信息,所以Client结构体就变成了这样 , 这时参数还比较少, 而且是必填的参数,我们可以提供构造函数来明确指定 。
看起来很满足,但是当我们需要增加一个 Timeout 参数来控制超时呢?
或许你会说这还不简单,像下面一样再加一个参数呗
那再加些其他的参数呢?那构造函数的参数是不是又长又串,而且每个参数不一定是必须的,有些参数我们又会考虑默认值的问题 。
为此,勤劳但尚未致富的 gophers 们使用了总结一种实践模式
首先提取所有需要的参数到一个独立的结构体 Options,当然你也可以用 Configs 啥的.
然后为每个参数提供设置函数
这样我们就为每个参数设置了独立的设置函数 。返回值func(*Options)看着有点不友好,我们提取下定义为单个Option调整一下代码
当我们需要添加更多的参数时,只需要在 Options 添加新的参数并添加新参数的设置函数即可 。
推荐阅读
- 直播抽烟技巧视频,直播抽烟技巧视频教学
- 自己的视频号怎么下载完整视频,自己的视频号怎么下载完整视频呢
- JavaScript聊天网站源代码,网页聊天系统源码
- u盘推荐什么牌子,u盘什么牌子好 速度快
- python量化损失函数的简单介绍
- html5元素块元素,html5article元素
- 团体角色扮演游戏,角色扮演游戏活动
- 移植常用命令到linux linux riscv移植
- 监控是什么样子视频,监控是什么样子视频播放器