在程序开发过程中我们经常需要去做性能测试、或性能排查方面的工作,而 Go 语言自带的 pprof 是个非常强大的工具,不仅使用简单而且可以用于线上服务性能的排查。
pprof 采样数据主要有三种获取方式:
runtime/pprof:手动调用 pprof API 来生成和写入采样文件,灵活性高。
net/http/pporf 通过 http 服务获取采样文件,简单易用,适用服务性能排查
go test 通过 go test -bench . -cpuprofile prof.cpu 获得采样文件,适用于对函数单独性能测试
我们这里演示下 net/http/pprof 的使用
基于web应用
IP 地址(Internet Protocol Address)是给每一个连接到互联网上的设备分配的一个全球唯一的标识符,也成为网际协议地址,IP 地址包括两类 IPv4 和 IPv6。
IPv4
在 TCP/IP 协议中,IP 地址是以二进制的形式表示的,共 32bit,为了方便记忆,我们一边使用十进制来记录比如:10.11.123.23。
IPv4 分类
A 类地址
A 类地址由 1 字节的网络地址和 3 字节的主机地址组成,且网络地址最高位为 “0”。
A 类地址网络数为 2^7=128,扣除两个保留地址:全是 0 的做为网络号,全是 1 的做为广播号。所以 A 类地址网络地址范围为 1
竞态检查器
go run -race main.go
编译反编译
// 编译
go build -gcflags="-S"
go tool compile -S hello.go
go tool compile -N -S hello.go // 禁止优化
// 反编译
go tool objdump <binary>
我们用 Go 写两个遍历两层 slice 的算法。
var items = make([][]int32, 1000)
func init() {
for i := 0; i < 1000; i++ {
items[i] = make([]int32, 1000)
for j := 0; j < 1000; j++ {
items[i][j] = rand.Int31n(2)
}
}
}
// 横向遍历
func sumRows() int {
var sum = 0
for
什么是基准测试
基准测试是测量一个程序在固定工作负载下的性能。我们通常会用来对比对同一个问题不同解决方案的性能,从而帮助我们做决定选择哪个方案更合理。
Go 的基准测试
Go 基准测试规则如下:
必须放在以 _test.go 结尾的文件中。
函数名必须以 Benchmark 开头
函数必须接受一个参数 *testing.B
没有返回值
基准测试受机器状态等因素的影响每次跑的结果很难保持完全一致,但是基本会在一个很小的范围内波动。
写一个简单的基准测试如下
import "testing"
func sum() int {
sum := 0
for i := 1; i &l
首先我们知道什么是流(stream),流物理设备的输入输出、存储设备上的文件的输入输出都映射到逻辑上的数据流,这是用来消除设备直接差异而抽象的一个概念。
通常情况下每个程序在启动的时候都会定义3个流:stderr、stdout、stderr,分别用来输入、输出、诊断和错误信息的输出,通常他们会被连接到用户终端(tty(4)),但是也可以修改到其他的文件和设备(重定向)。这取决于双亲进程的选择和设置。
Linux的本质是一切皆是文件,输入输出设备也是使用文件的形式存在和管理的,内核启动的时候默认会打开三个I/O设备文件:stdin、stdout、stderr,分别得到的描述符是0,1,2,并且他
我们在应用调试或者线上业务中经常会用到日志功能,而 Go 语言内置了 log 模块。
log 模块的使用
先来看下 log 模块的基本使用:
package main
import (
"log"
)
func main() {
log.Println("hello log.Println")
log.Printf("hello %s", "log.Printf")
}
我们运行一下可以看到如下输出:
> $ go run main.go
2018/10/29 10:45:39 hello log.Println
2018/10/29 10:45:39 hel
冒泡排序是最基本的排序算法,它的复杂度为O(n²)。
它的实现原理非常简单,就是从头遍历数组,如果第 i 个数比第 i + 1 个数大,那么就交换他们,这样遍历第一次就会让最大的数放到数组末尾,第二遍会把第二大的数放到数组倒数第二的位置,依次类推……
冒泡排序过程图形表示如下:
那么我们可以实现最基本的冒泡排序如下:
func BubbleSort1(list []int) {
n := len(list)
for i := 0; i < n; i++ {
for j := 0; j < n-1; j++ {
if list
整数类型
MySQL 包含以下几种整数类型:TINYINT SMALLINT MEDIUMINT INT BIGINT,分别使用8,16,24,32,64位存储空间。他们可以存储的范围为-2^(n-1)到2^(n-1)-1,其中 n 是存储空间位数。
整数类型有可选的 UNSIGNED 属性,表示不允许负数,这大致可以使正数的上限提升一倍,2^n - 1。有符号和无符号的使用相同的存储空间,并且具有相同的性能。
MySQL 可以为正数指定宽度,例如INT(11),对大多数应用没有意义,它不会限制值得合法范围,只是规定了 MySQL 的一些交互工具用来展示字符的个数而已。对于存储和计算来说 IN
MySQL支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要。不管存储哪种数据类型,下面几个简单的原则都有助于做出更好的选择。
更小的通常更好
一般情况下,尽可能使用可以正确存储数据的最小数据类型。更小的数据类型通常更快,因为他们占用的更少的磁盘、内存和CPU缓存,处理时需要的CPU周期更少。
简单最好
简单的数据类型的操作通常需要更少的CPU周期。例如整数比字符操作代价更低,因为字符集和校对规则使字符串比较比整型更复杂。
两个实际使用中的例子,一个是使用MySQL内置的类型而不是字符串存储时间,另一个是使用整型而不是字符串存储IP。
尽量避免NULL
很多表都包含可为 NULL