[转]Go 程序的性能调试问题

2015-03-30 06:10:13 查看评论 1862 人阅读    

假设你手上有个Go语言编写的程序,你打算提升它的性能。目前有一些工具可以为此提供帮助。这些工具能帮你发现包括CPU、IO和内存在内多种类型的热点。所谓热点,是指那些为了能显著提升性能而值得你去关注的地方。有时候这些工具还能帮助你发现程序中主要的性能瑕疵。举个例子,你没必要每次执行SQL查询前都对SQL语句进行参数化解析,你可以将这个准备过程在程序启动时一次完成。再举个例子,当前某个算法的复杂度是O(N²),但其实存在一个复杂度是O(N)的解决方案。为了能发现这些问题,需要理智地检查你在优化分析器中获取到的信息。比如上面提到的第一个问题,你会注意到相当长的时间被花费在了对SQL语句的准备上。

了解针对性能的不同边界因素也是比较重要的。比方说,如果一个程序使用100 Mbps带宽的网络进行通信,而目前已经占用了超过90 Mbps的带宽,为了提升它的性能,你拿这样的程序也没啥办法了。在磁盘IO、内存消耗和计算密集型任务方面,也有类似的边界因素。

将这点牢记在心,让我们看看有哪些工具可以用。

注意:这些工具会彼此互相影响。例如,对内存使用优化分析器会导致针对CPU的优化分析器产生误差,对goroutine阻塞使用优化分析器会影响调度器跟踪等等。为了获得更加精确的信息,请在隔离的环境中使用这些工具。

注意:本文描述的用法基于Go语言发布的1.3版。


CPU 分析器

Go 运行时包含了内建的CPU分析器,它用来展示某个函数耗费了多少CPU百分时间。这里有三种方式来使用它:

1. 最简单的是用"go test"的-cpuprofile选项。例如下面的命令:

$ go test -run=none -bench=ClientServerParallel4 -cpuprofile=cprof net/http

将会分析所给的基准并将结果写入"cprof"文件中。

然后:

$ go tool pprof --text http.test cprof

将会打印耗费最多CPU时间的函数列表。

这里有几种可用的输出形式,最实用的有 --text, --web 和 --list。运行 "go tool pprof" 来得到完整的列表。

这个选项最明显的缺点是它只能用来做测试。

2. net/http/pprof 包。这是网络服务器的理想解决方案。你可能仅仅需要导入net/http/pprof,然后使用下面的方法收集分析结果:

$ go tool pprof --text mybin http://myserver:6060:/debug/pprof/profile

3. 手动收集. 你需要导入 runtime/pprof 然后再main函数中添加下面的代码:

1   if *flagCpuprofile != "" {
2       f, err := os.Create(*flagCpuprofile)
3       if err != nil {
4           log.Fatal(err)
5       }
6       pprof.StartCPUProfile(f)
7       defer pprof.StopCPUProfile()
8   }

分析结果会被写入指定的文件中,像第一种方式一样使之可视化。

这里有一个使用 --web 选项来实现可视化的例子:

cpu profile


Golang遍历目录删除过期文件

2014-07-18 19:16:59 查看评论 1478 人阅读    

挺简单的一个遍历删除,直接上代码

package main

import (
	"fmt"
	"os"
	"path/filepath"
	"time"
)

const (
	DAY  = 10       //过期的天数
	HOUR = DAY * 24 //用于判断过期的小时数
)

func main() {
	path := "F:/test" //需要删除的路径

	//遍历目录
	err := filepath.Walk(path, 
	    func(path string, f os.FileInfo, err error) error {
		if f == nil { //获取文件数据为空则直接返回
			fmt.Println("Get FileInfo Nil: ", path)
			return nil
		}
		os.Chmod(path, 0777) //设置目录或者文件的可操作权限
		//判断文件的最后修改时间是否大于过期时间
		isExpired := int(time.Now().Sub(f.ModTime()).Hours()) > HOUR
		if !f.IsDir() && isExpired { //属于文件类型且已经过期则直接删除
			err := os.Remove(path)
			if err != nil {
				fmt.Println("Remove File Error:", err)
				return nil //删除失败仍旧继续
			} else {
				fmt.Println("Remove File: ", path)
			}
		}
		return nil
	})
	if err != nil {
		fmt.Println("Err:", err)
	}
}

代码附件:fileclear.rar