0%

Golang学习(一)

闲扯

去北京参加Top100学习到现在一个多月过去了,时间过得好快,转眼2017年只剩下最后一周了,不由得感叹时间就像指缝的流沙。
再加上最近中年程序员不堪重负的各种新闻,感觉自己距离那一天也没多远了,在此之前努力提高自己的姿势水平吧,要没时间了。

在Top100听到了很多讲师提到了Golang,结合之前看过的左耳朵耗子的文章《GO语言、DOCKER 和新技术》,决定要学习了解下Golang了。
最近半个月断断续续看了Golang的一些教程《GO 语言简介(上)— 语法》《GO 语言简介(下)— 特性》、无闻老师的《Go 编程基础》,只是对Golang有了一点点初步的了解。
学习一门语言最重要的还是要撸代码啊,要动手写个小工具试试手。
恰巧昨天加班时帮同事写了个小工具,感觉用Python的性能不够好,而且想要高性能还要依赖gevent这种第三方库,不方便部署,于是想到用Golang可以来试下,写完编译下给同事用就好啦!昨晚回到家吃过饭陪女朋友玩了会,从十点开始撸代码到凌晨一点,终于写出一个小demo,特此记录下年轻人的第一个Golang小程序。


正文

工具需求是有一个样例zip包,zip包里面有一些bcp数据、xml数据、bjson数据、图片、视频什么的。
zip包的命名规范如下:
​ AAA-BBB-1514090969-CCC_DDD_21234.zip
我们要将zip包的1514090969【绝对秒数】与21234【随机序列】进行替换,随机生成大量的zip包副本,发送到某个ETL输入目录,暂且不管zip包里面的内容(其实zip包内的文件也要随机生成)。
之前同事用Shell写的,没看他代码怎么实现的,不过肯定有问题,一小时才生成了三万个样例zip包,远远达不到压测的要求。
于是我花了十几分钟调用Python的gevent模块帮他重新用Python写了一遍,性能瞬间爆炸。
但是部署gevent比较麻烦(公司和客户都是内网环境,pip是没法用的,只能手动安装所需的第三方包,而且公司大部分操作系统还是Redhat AS6U3,默认的Python是2.6版本,各种不方便),就想到了如果用Golang写一遍是否性能很好,编译后提供二进制文件直接运行就可以了,于是就有了下面的代码。

代码

1
/*
2
 * User: toddlerya
3
 * Date: 2017/12/23
4
 * ds接入模块加压工具
5
 */
6
7
package main
8
9
import (
10
	"flag"
11
	"fmt"
12
	"io"
13
	"math/rand"
14
	"os"
15
	"strconv"
16
	"strings"
17
	"time"
18
)
19
20
func judgeExists(name string) bool {
21
	if _, err := os.Stat(name); err != nil {
22
		if os.IsNotExist(err) {
23
			return false
24
		}
25
	}
26
	return true
27
}
28
29
func copyFile(src, des string) (w int64, err error) {
30
	srcFile, err := os.Open(src)
31
	if err != nil {
32
		fmt.Println(err)
33
	}
34
	defer srcFile.Close()
35
36
	desFile, err := os.Create(des)
37
	if err != nil {
38
		fmt.Println(err)
39
	}
40
	defer desFile.Close()
41
42
	return io.Copy(desFile, srcFile)
43
}
44
45
func generateRandomNumber(start int, end int) int {
46
	if end < 0 || start < 0 || (end-start) <= 0 {
47
		fmt.Println("[-] 随机数起始值[start]必须大于等于0, 截至值[end]必须大于起始值!")
48
		fmt.Printf("[-] 请检查配置是否正确: start=%v, end=%v\n", start, end)
49
		panic("随机数参数错误")
50
	}
51
	rand.Seed(time.Now().UnixNano())
52
	num := rand.Intn((end - start)) + start
53
	return num
54
}
55
56
func main() {
57
	srcFilePath := flag.String("s", "/home", "输入原始文件路径")
58
	dstFilePath := flag.String("d", "/tmp", "目标输出路径")
59
	renameFormat := flag.String("f", "abc-{random1}-456_780_{random2}.zip", "参数原始文件替换格式")
60
	random1Start := flag.Int("r1s", 100, "随机参数1的起始值")
61
	random1End := flag.Int("r1e", 999, "随机参数1的截止值")
62
	random2Start := flag.Int("r2s", 100000, "随机参数2的起始值")
63
	random2End := flag.Int("r2e", 999999, "随机参数2的截止值")
64
	generateFileNumber := flag.Int("g", 10000, "需要生成的文件个数")
65
	// taskQueueSize := flag.Int("t", 100, "每次任务队列生成文件个数")
66
	// interval := flag.Int("i", 3, "任务运行间隔[单位秒]")
67
	flag.Parse()
68
	fmt.Printf("[srcFilePath]          :%s\n", *srcFilePath)
69
	fmt.Printf("[dstFilePath]          :%s\n", *dstFilePath)
70
	fmt.Printf("[renameFormat]         :%s\n", *renameFormat)
71
	fmt.Printf("[random1Start]         :%v\n", *random1Start)
72
	fmt.Printf("[random1End]           :%v\n", *random1End)
73
	fmt.Printf("[random2Start]         :%v\n", *random2Start)
74
	fmt.Printf("[random2End]           :%v\n", *random2End)
75
	fmt.Printf("[generateFileNumber]   :%v\n", *generateFileNumber)
76
	// fmt.Printf("[taskQueueSize]        :%v\n", *taskQueueSize)
77
	// fmt.Printf("[interval](second)     :%v\n", *interval)
78
	fmt.Println("=======================================")
79
	if judgeExists(*srcFilePath) {
80
		fmt.Println("[+] 开始随机生成目标数据, 请注意", *dstFilePath, "目录是否有数据生成\t", "计划生成", *generateFileNumber, "个文件Orz")
81
		count := 0
82
		for {
83
			if count >= *generateFileNumber {
84
				fmt.Println("[+] 已经完成目标: 共计生成", *generateFileNumber, "个文件")
85
				return
86
			}
87
			random1Val := generateRandomNumber(*random1Start, *random1End)
88
			random2Val := generateRandomNumber(*random2Start, *random2End)
89
			temp := strings.Replace(*renameFormat, "{random1}", strconv.Itoa(random1Val), -1)
90
			newFileName := strings.Replace(temp, "{random2}", strconv.Itoa(random2Val), -1)
91
			dstJoinList := []string{*dstFilePath, newFileName}
92
			newDstFilePath := strings.Join(dstJoinList, "/")
93
			fmt.Println("[*] 输出随机生成的文件: ", newDstFilePath)
94
			copyFile(*srcFilePath, newDstFilePath)
95
			count++
96
		}
97
	} else {
98
		fmt.Println("[-] 原始文件不存在, 请检查: ", *srcFilePath)
99
	}
100
}

使用效果如下

测试运行

异常处理

遗留BUG

但是在阿里云的测试中发现了程序的BUG,df看磁盘剩余空间还有很多,但是df -i查看发现磁盘Inode被耗尽了导致无法复制文件,可是是程序并没有停止复制,异常退出,这个BUG以后再修改:

后续

因为还没学到Golang的并发,所以这个demo只是简单的循环执行,后续学会了并发再来更新T_T


2017年12月24日 于 南京
Email
GitHub