golang 实战 对树形结构的数据进行遍历
刚刚学习了一门新的语言,网络参考了一篇对树形结构的数据进行遍历,准备自己动手操作一下。
生成示例文件
因为都python 比较熟悉还是使用python 进行示例文件的生成,生成1000个文件夹,每个文件夹里面有1000个空文件。准备运用 golang 数出文件的个数。
建立一个python文件 files.py 代码如下:
import os
import datetime
def mkfiles(dir: str, i: str):
file = open(f'{dir}/test{i}' + '.txt', 'w')
def mkdir(dir: str):
os.mkdir(dir)
def main(dirs=1000, files=1000, maindir="files/"):
start = datetime.datetime.now()
mkdir(maindir)
for i in range(dirs):
mkdir(maindir + str(i))
for j in range(files):
mkfiles(maindir + str(i), str(j))
end = datetime.datetime.now()
print(end - start)
main()
$ python files.py
0:00:44.356719
运行代码,使用python 生成1000个文件夹,每个文件夹里面有1000个空文件,
使用单线程读取文件数目
定义go执行文件 main.go,编写golang 代码读取特定文件夹的文件数目。
package main
import (
"fmt"
"io/ioutil"
"time"
)
var matches int // 文件的个数
func main() {
start := time.Now()
search("/home/theing/go/go_study/study/")
fmt.Println(matches, "matches") //打印找到的文件个数
fmt.Println(time.Since(start))
}
func search(path string) {
files, err := ioutil.ReadDir(path)
if err == nil { // 如果没有错误
for _, file := range files { //遍历这些文件
name := file.Name()
if file.IsDir() { // 如果是文件夹就递归调用打开
search(path + name + "/")
} else {
matches++
}
}
}
}
$ pwd
/home/theing/go/go_study/study
$ go run main.go
$ # 或者 go build main.go && ./main
1000001 matches
3.082080437s
三秒就完成了???
golang 使用 多线程读取文件
package main
import (
"fmt"
"io/ioutil"
"time"
)
var matches int // 文件的个数
var workerCount = 0 //用于定义当前工人的数量
var maxWorkerCount = 8 //最大的工人数量
var searchRequest = make(chan string) // 定义一个channel用来包工头指派活
var workerDone = make(chan bool) // 用户工人之间的交流,自己是否干完活了
var foundMatch = make(chan bool) // 用来传输工人找到了多少结果的消息
func main() {
start := time.Now()
workerCount = 1 //初始化当前的工人数 至少都是一个
go search("/home/theing/go/go_study/study/", true) //因为需要等待所有的工人把活干完主函数才能结束,所有加一个bool值
waitForWorkers() //等待这些工人干活
fmt.Println(matches, "matches") //打印找到的文件个数
fmt.Println(time.Since(start))
}
func waitForWorkers() {
for { //写一个无线循环,不停的接收
select {
case path := <-searchRequest: // 指派一个工人去这里
workerCount++ // 当前工人数量加1
go search(path, true) // true 表示正在干活
case <-workerDone: //如果有工人做完了
workerCount-- //工人数量减一
if workerCount == 0 { // 如果工人数量减为零了就结束
return
}
case <-foundMatch: //找到了结果就加一
matches++
}
}
}
func search(path string, master bool) {
files, err := ioutil.ReadDir(path)
if err == nil { // 如果没有错误
for _, file := range files { //遍历这些文件
name := file.Name()
if file.IsDir() { // 如果是文件夹就递归调用打开
if workerCount < maxWorkerCount { // 看看当前剩余的工人
searchRequest <- path + name + "/" //如果有的话就叫包工头给这里指派一个工人
} else {
search(path+name+"/", false) // 当没有工人的时候就传 false 。
}
} else {
foundMatch <- true // 工人喊话,我找到了
}
}
if master {
workerDone <- true // 如果是在gorount中运行的函数,for循环完毕了就告诉包工头干完了。
}
}
}
运行代码
$ go run main.go
1000001 matches
1.63184361s
1.6秒,,,爽歪歪