本文目录一览:
- 1、golang-redis系列——返回值助手函数(二)
- 2、怎么学习golang
- 3、golang性能测试框架k6源码分析
- 4、bpftrace动态追踪golang应用-函数内联问题
- 5、golang是什么意思
golang-redis系列——返回值助手函数(二)
从上一节的内容可知,Do() 和 Receive() 等方法的返回值,除了 error 外,是一个 interface{} 类型的返回值,因此当我们的复杂操作返回的不是基本数据类型时,就需要我们自己解析返回值,例如,当我们利用 HMGET 方法获取一批返回值时,就需要对返回结果进行解析,具体如下:
由于返回值是多条数据,因此需要先将 reply 转成 []interface 类型,然后在遍历结果时在分别转成 []uint8 (byte数组), 最后再转成 string 类型。
随着我们操作复杂度,数据解析的工作量也会非常大,(lua 脚本的使用,会使结果的解析更为复杂,因为可能存在多种类型的结果一起返回的情况,lua 脚本相关的内容会在下一节介绍)。
redigo 包中的返回值助手函数的存在,就是为了帮助我们完成这些枯燥繁琐的数据解析过程。
返回值助手函数相关源码路径为 github.com/gomodule/redigo/redis/reply.go 提供的主要方法如下:
上述返回值助手函数的具体使用,应该依据具体的命令进行选择。如果大家还记得上一节介绍的 Redis 基本数据类型,可能会有些疑问,对于 redis 来说,其数据据存储本质都是 []bytes, 为什么可以解析出 Int、int64、float等类型的数据呢?
我们以 Float64() 为例进行说明,具体源码如下:
其实,返回值助手函数是将 []byte 类型的原始数据,利用 strconv.ParseFloat(string(reply), 64) 转换成了 float64类型,因此在我们使用过程中返回值助手函数的选择,应该基于业务和实际存储的数据格式为依据。我们以第一小节的示例为例,看返回值助手函数如何降低我们的工作量,具体如下:
除了使用返回值助手函数对上述固定结构的结果进行解析外,redigo 包还提供了一个 Scan()函数用于解析自定义的复杂数据结构,我们依然以上一个示例进行说明,具体示例如下:
如果返回结果为结构化切片,也可以使用 canSlice() 方法,从而简化 loop 处理的部分,具体示例如下:
通过上述的示例,我们介绍了 scan 函数的基本用法,但是细心的同学可能会发现吗,为什么数据写入时,value 的类型为 []int64 但是读取时只能按照 string 类型读取呢。这是因为 Redis 底层存储的数据本质都是 string 类型,。 无论是 HMSET 还是 MSET 最终都只能按照 string 类型读取,因为其本质都是 hash 结构,不同之处仅在于 HMSET 是嵌套的 hash类型。 因此,[]int64 数据在写入阶段,就已经被自动处理为 []byte,写入 redis 之后,len 和 类型 属性会丢失。
如果强行按照 []int64解析将出错:
如果 value 必须以结构化的数据存储,那么可以提前对要写入的数据进行编码,例如 json、protobuf 等,取出后再进行解码获得原始数据。
怎么学习golang
已经有好多程序员都把Go语言描述为是一种所见即所得(WYSIWYG)的编程语言。这是说,代码要做的事和它在字面上表达的意思是完全一致的。 在这些新语言中,包含D,Go,Rust和Vala语言,Go曾一度出现在TIOBE的排行榜上面。与其他新语言相比,Go的魅力明显要大很多。Go的成熟特征会得到许多开发者的欣赏,而不仅仅是因为其夸大其词的曝光度。下面我们来一起探讨一下谷歌开发的Go语言以及谈谈Go为什么会吸引众多开发者: 快速简单的编译 Go编译速度很快,如此快速的编译使它很容易作为脚本语言使用。关于编译速度快主要有以下几个原因:首先,Go不使用头文件;其次如果一个模块是依赖A的,这反过来又取决于B,在A里面的需求改变只需重新编译原始模块和与A相依赖的地方;最后,对象模块里面包含了足够的依赖关系信息,所以编译器不需要重新创建文件。你只需要简单地编译主模块,项目中需要的其他部分就会自动编译,很酷,是不是? 通过返回数值列表来处理错误信息 目前,在本地语言里面处理错误的方式主要有两种:直接返回代码或者抛异常。这两种都不是最理想的处理方式。其中返回代码是非常令人沮丧的,因为返回的错误代码经常与从函数中返回的数据相冲突。Go允许函数返回多个值来解决这个问题。这个从函数里面返回的值,可以用来检查定义的类型是否正确并且可以随时随地对函数的返回值进行检查。如果你对错误值不关心,你可以不必检查。在这两种情况下,常规的返回值都是可用的。 简化的成分(优先于继承) 通过使用接口,类型是有资格成为对象中一员的,就像Java指定行为一样。例如在标准库里面的IO包,定义一个Writer来指定一个方法,一个Writer函数,其中输入参数是字节数组并且返回整数类型值或者错误类型。任何类型实现一个带有相同签名的Writer方法是对IO的完全实现,Writer接口。这种是解耦代码而不是优雅。它还简化了模拟对象来进行单元测试。例如你想在数据库对象中测试一个方法,在标准语言中,你通常需要创建一个数据库对象,并且需要进行大量的初始化和协议来模拟对象。在Go里面,如果该方法需要实现一个接口,你可以创建任何对该接口有用的对象,所以,你创建了MockDatabase,这是很小的对象,只实现了几个需要运行和模拟的接口——没有构造函数,没有附件功能,只是一些方法。 简化的并发性 相对于其他语言,并发性在Go里面显得更加容易。把‘go’关键字放在任意函数前面然后那个函数就会在其go-routine自动运行(一个很轻的线程)。go-routines是通过通道进行交流并且基本上封锁了所有的队列消息。普通工具对相互排斥是有用,但是Go通过使用通道来踢掉并发性任务和坐标更加容易。 优秀的错误消息 所有与Go相似的语言,自身作出的诊断都是无法与Go相媲美的。例如,一个死锁程序,在Go运行时会通知你目前哪个线程导致了这种死锁。编译的错误信息是非常详细全面和有用的。 其他 这里还有许多其他吸引人的地方,下面就一概而过的介绍一下,比如高阶函数、垃圾回收、哈希映射和可扩展的数组内置语言(部分语言语法,而不是作为一个库)等等。 当然,Go并不是完美无瑕。在工具方面还有些不成熟的地方和用户社区较小等,但是随着谷歌语言的不断发展,肯定会有整治措施出来。尽管许多语言,尤其是D、Rust和Vala旨在简化C++并且对其进行简化,但它们给人的感觉仍是“C++看上去要更好”。
【Go语言的优势】
可直接编译成机器码,不依赖其他库,glibc的版本有一定要求,部署就是扔一个文件上去就完成了。
静态类型语言,但是有动态语言的感觉,静态类型的语言就是可以在编译的时候检查出来隐藏的大多数问题,动态语言的感觉就是有很多的包可以使用,写起来的效率很高。
语言层面支持并发,这个就是Go最大的特色,天生的支持并发,我曾经说过一句话,天生的基因和整容是有区别的,大家一样美丽,但是你喜欢整容的还是天生基因的美丽呢?Go就是基因里面支持的并发,可以充分的利用多核,很容易的使用并发。
内置runtime,支持垃圾回收,这属于动态语言的特性之一吧,虽然目前来说GC不算完美,但是足以应付我们所能遇到的大多数情况,特别是Go1.1之后的GC。
简单易学,Go语言的作者都有C的基因,那么Go自然而然就有了C的基因,那么Go关键字是25个,但是表达能力很强大,几乎支持大多数你在其他语言见过的特性:继承、重载、对象等。
丰富的标准库,Go目前已经内置了大量的库,特别是网络库非常强大,我最爱的也是这部分。
内置强大的工具,Go语言里面内置了很多工具链,最好的应该是gofmt工具,自动化格式化代码,能够让团队review变得如此的简单,代码格式一模一样,想不一样都很困难。
跨编译,如果你写的Go代码不包含cgo,那么就可以做到window系统编译linux的应用,如何做到的呢?Go引用了plan9的代码,这就是不依赖系统的信息。
内嵌C支持,前面说了作者是C的作者,所以Go里面也可以直接包含c代码,利用现有的丰富的C库。
golang性能测试框架k6源码分析
k6是新兴的性能测试框架,比肩jmeter,另外测试脚本使用js,更加适合自动化的架构。
k6启动的框架是使用golang的cli标准框架cobra,入口函数
进入cobra框架后,我们直接查看getRunCmd,这个是命令run的入口,主要工作都是从这里开始。
重点关注初始化Runner,这个是通过js脚本,使用goja库解析后,生成的实际执行单元。
进入js目录,查看Runner的结构,runner.go
Runner有一些配置属性,另外还有方法,方法用lib.Runner的接口进行规范。
Runner有一个NewVU方法,里面定义了连接参数,实现api测试
返回主函数,在初始化完成Runner后,启动调度器,以及做结果收集
最终封装成一个engine
启动测试
bpftrace动态追踪golang应用-函数内联问题
在上一篇文章的golang代码中,函数add的上一行,增加了一条注释语句: //go:noinline 。在bpftrace追踪时,是否可以去掉?有什么作用?
为了说明该问题,设计一个例子。
golang代码中,有两个求和函数。其中,add1加上 //go:noinline ,另一个add2不加。代码如下:
bpftrace程序分别对函数add1和add2的输入参数、返回值进行追踪,代码如下:
执行程序后,可以看到bpftrace程序能够正常追踪到函数add1,但是无法追踪到函数add2。
通过上文中的示例代码,可以看到,没有加 //go:noinline 的函数无法被bpftrace程序追踪到。通过查阅golang相关文档,可以知道, //go:noinline 表示该函数在编译时,不会被内联。
使用 objump -S 生成golang程序的汇编代码如下:
通过汇编代码,我们可以看到,主函数中,地址 0x498e52 处 callq 498e00 调用了add1函数,地址 0x498ebb 处 movq $0x4,(%rsp) 直接计算求值。
因此,golang编译器在编译代码时,会对代码进行分析,并按照内联规则,将某些函数生成内联代码。一旦函数被内联,bpftrace将无法追踪到对应函数。也就是,上文中函数 add2 无法被追踪到。
针对golang程序中编译器内联的问题,可以通过禁止内联的方式来解决。禁止内联的方式有:
在实践中,可以通过 go build -gcflags="-m -m" 来查看,哪些函数会在编译时执行内联,如:
从输出中,可以看到:
关于golang编译器进行内联的场景,可以参考golang源码:。
由于golang编译器内联优化,bpftrace可能无法正常追踪golang程序。在编写bpftrace脚本时,可以先使用 nm 命令查看一下可执行程序,是否存在需要追踪的函数的符号信息。如果没有则bpftrace将不能对其进行追踪。
前面的示例中,都是对 int 类型的参数进行追踪,那对于 string 类型的参数,是否也可以用同样的方式进行追踪?将在下一篇中进行讨论。
golang是什么意思
Go语言(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译型语言。Go 语言语法与 C 相近,但功能上有:内存安全,GC(垃圾回收),结构形态及 CSP-style 并发计算。 扩展资料
Go语言主要用作服务器端开发,其定位是用来开发“大型软件”的,适合于很多程序员一起开发大型软件,并且开发周期长,支持云计算的网络服务。Go语言能够让程序员快速开发,并且在软件不断的'增长过程中,它能让程序员更容易地进行维护和修改。它融合了传统编译型语言的高效性和脚本语言的易用性和富于表达性。
Go语言作为服务器编程语言,很适合处理日志、数据打包、虚拟机处理、文件系统、分布式系统、数据库代理等;网络编程方面,Go语言广泛应用于Web应用、API应用、下载应用等;除此之外,Go语言还可用于内存数据库和云平台领域,目前国外很多云平台都是采用Go开发。