Go性能优化:map使用注意事项

内置 map 类型是必须的。首先,该类型使用频率很高;其次,可借助 runtime 实现深层次优化(比如说字符串转换,以及 GC 扫描等)。可尽管如此,也不意味着万事大吉,依旧有很多需特别注意的地方。

1、预设容量

map 会按需扩张,但须付出数据拷贝和重新哈希成本。如有可能,应尽可能预设足够容量空间,避免此类行为发生。

从结果看,预设容量的 map 显然性能更好,更极大减少了堆内存分配次数。

 

Continue reading “Go性能优化:map使用注意事项”

Go性能优化:string与[ ]byte转换

字符串(string)作为一种不可变类型,在与字节数组(slice, [ ]byte)转换时需付出 “沉重” 代价,根本原因是对底层字节数组的复制。这种代价会在以万为单位的高并发压力下迅速放大,所以对它的优化常变成 “必须” 行为。

首先,须了解 string 和 [ ]byte 数据结构,并确认默认方式的复制行为。

动态演示: https://asciinema.org/a/6up6gvgqo0v9zkjpusvyucg8g

Continue reading “Go性能优化:string与[ ]byte转换”

Go性能监控/分析工具:go tool pprof

我们可以使用go tool pprof命令来交互式的访问概要文件的内容。命令将会分析指定的概要文件,并会根据我们的要求为我们提供高可读性的输出信息。

在Go语言中,我们可以通过标准库的代码包runtimeruntime/pprof中的程序来生成三种包含实时性数据的概要文件,分别是CPU概要文件、内存概要文件和程序阻塞概要文件。下面我们先来分别介绍用于生成这三种概要文件的API的用法。

CPU概要文件

在介绍CPU概要文件的生成方法之前,我们先来简单了解一下CPU主频。CPU的主频,即CPU内核工作的时钟频率(CPU Clock Speed)。CPU的主频的基本单位是赫兹(Hz),但更多的是以兆赫兹(MHz)或吉赫兹(GHz)为单位。时钟频率的倒数即为时钟周期。时钟周期的基本单位为秒(s),但更多的是以毫秒(ms)、微妙(us)或纳秒(ns)为单位。在一个时钟周期内,CPU执行一条运算指令。也就是说,在1000 Hz的CPU主频下,每1毫秒可以执行一条CPU运算指令。在1 MHz的CPU主频下,每1微妙可以执行一条CPU运算指令。而在1 GHz的CPU主频下,每1纳秒可以执行一条CPU运算指令。

在默认情况下,Go语言的运行时系统会以100 Hz的的频率对CPU使用情况进行取样。也就是说每秒取样100次,即每10毫秒会取样一次。为什么使用这个频率呢?因为100 Hz既足够产生有用的数据,又不至于让系统产生停顿。并且100这个数上也很容易做换算,比如把总取样计数换算为每秒的取样数。实际上,这里所说的对CPU使用情况的取样就是对当前的Goroutine的堆栈上的程序计数器的取样。由此,我们就可以从样本记录中分析出哪些代码是计算时间最长或者说最耗CPU资源的部分了。我们可以通过以下代码启动对CPU使用情况的记录。

在函数startCPUProfile中,我们首先创建了一个用于存放CPU使用情况记录的文件。这个文件就是CPU概要文件,其绝对路径由*cpuProfile的值表示。然后,我们把这个文件的实例作为参数传入到函数pprof.StartCPUProfile中。如果此函数没有返回错误,就说明记录操作已经开始。需要注意的是,只有CPU概要文件的绝对路径有效时此函数才会开启记录操作。

如果我们想要在某一时刻停止CPU使用情况记录操作,就需要调用下面这个函数:

在这个函数中,并没有代码用于CPU概要文件写入操作。实际上,在启动CPU使用情况记录操作之后,运行时系统就会以每秒100次的频率将取样数据写入到CPU概要文件中。pprof.StopCPUProfile函数通过把CPU使用情况取样的频率设置为0来停止取样操作。并且,只有当所有CPU使用情况记录都被写入到CPU概要文件之后,pprof.StopCPUProfile函数才会退出。从而保证了CPU概要文件的完整性。 Continue reading “Go性能监控/分析工具:go tool pprof”

Go语言中需要注意结构体方法副本传参与指针传参的区别

我们来看个例子:

执行后结果如下:

可以看到Test1中打印出b结构体的地址在变化,而Test2中没有变化,这说明每一次Test1的调用,都是传入的结构体b的一个副本(拷贝),当在Test1中对内部变量的任何改动,都将会失效(因为下一次访问的时候传入的是b结构体新的副本)。而Test2方法作为指针传参时,每一次传入的都是b结构体的指针,指向的是同一个结构体,因此地址没有变化,且对内部变量做改动时,都是改动的b结构体内容。

在Go语言中的这个差别可能是对OOP设计的一个坑,在Go语言中要想实现OOP的设计,在进行方法封装时,都采用Test2的写法。 Continue reading “Go语言中需要注意结构体方法副本传参与指针传参的区别”

JetBrains 出品的 Go 集成开发环境 GogLand 发布正式版

一直用Gogland的公测版本,从本月初发布了正式版(名字改成Goland了),使用了一下,整体功能和公测版差别不大,希望一些异常崩溃的问题得到了解决。

下载地址:

Linux:https://download.jetbrains.com/go/goland-2017.3.tar.gz 
Windows:https://download.jetbrains.com/go/goland-2017.3.exe 
macOS:https://download.jetbrains.com/go/goland-2017.3.dmg

Linsence Server:http://xidea.online

虽然有破解版,看了一下个人版本一年才89刀,支持下正版。

Go语言slice基本操作

 

Go使用mmap的例子

 

Go之strings、buffers、bytes、binary包

strings包

strings包的使用举例:

Continue reading “Go之strings、buffers、bytes、binary包”

Go序列化反序列化二进制包

二进制操作示例:

可以做一下封装,简化操作,其中需要注意的是,二进制的打包与解包,需要传入确定的数据类型变量,以便binary包能自动识别变量长度: