golang实战 对树形结构的数据进行遍历


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秒,,,爽歪歪


文章作者: theing
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 theing !
评论
  目录