[日常] Go语言圣经-示例: 并发的目录遍历习题
2023-02-18 15:47:10 时间
练习 8.9: 编写一个du工具,每隔一段时间将root目录下的目录大小计算并显示出来。
package main import ( // "filepath" "flag" "fmt" "io/ioutil" "os" "path" "sync" "time" ) /* 练习 8.9: 编写一个du工具,每隔一段时间将root目录下的目录大小计算并显示出来。 */ //接收命令行参数-v var verbose = flag.Bool("v", false, "show verbose progress messages") func main() { //接收命令行参数,多个路径 flag.Parse() roots := flag.Args() //如果没传递任何路径,给默认值 if len(roots) == 0 { roots = []string{"/"} } for { sumFileSize(roots) time.Sleep(20 * time.Second) } } func sumFileSize(roots []string) { //发送和接收文件字节大小的channel fileSizes := make(chan int64) //goroutine的计数器 var n sync.WaitGroup //循环命令行传递的路径 for _, root := range roots { n.Add(1) //启动goroutine计算 go walkDir(root, &n, fileSizes) } //启动goroutine,等待所有计算目录的goroutine结束 go func() { n.Wait() close(fileSizes) }() //定时显示目录进度发送的channel var tick <-chan time.Time if *verbose { tick = time.Tick(500 * time.Millisecond) } var nfiles, nbytes int64 //select和loop循环,多路复用 loop: for { select { case size, ok := <-fileSizes: if !ok { break loop // fileSizes was closed } //计算目录数,计算字节大小 nfiles++ nbytes += size case <-tick: //接收到定时channel打印进度 printDiskUsage(nfiles, nbytes) } } //最后打印总计 printDiskUsage(nfiles, nbytes) // final totals } func walkDir(dir string, n *sync.WaitGroup, fileSizes chan<- int64) { defer n.Done() for _, entry := range dirents(dir) { if entry.IsDir() { n.Add(1) subdir := path.Join(dir, entry.Name()) //开启多个goroutine进行递归 go walkDir(subdir, n, fileSizes) } else { fileSizes <- entry.Size() } } } var sema = make(chan struct{}, 20) // dirents returns the entries of directory dir. func dirents(dir string) []os.FileInfo { //使用计数信号量逻辑限制太多并发 sema <- struct{}{} entries, err := ioutil.ReadDir(dir) <-sema if err != nil { fmt.Fprintf(os.Stderr, "du1: %v\n", err) return nil } return entries } func printDiskUsage(nfiles, nbytes int64) { fmt.Printf("%d files %.1f GB\n", nfiles, float64(nbytes)/1e9) }
相关文章
- GoLand激活码2022(2022Goland最新激活码)
- 底层逻辑-理解Go语言的本质
- 使用VMware虚拟机安装kali Linux
- 干货分享丨从MPG 线程模型,探讨Go语言的并发程序
- Linux系列(41) - 监听命令Vmstart,Top(还需完善)
- Linux系列(40) - 自动同步时间chrony
- Linux系列(39) - nohup
- Jmeter系列(10)- Linux环境安装之Jmeter下载配置
- Jmeter系列(9)- Linux环境安装之安装JDK
- Linux系列(38) - 源码包安装(2)
- Linux系列(37) - 源码包与RPM包区别(1)
- Linux系列(36) - yum命令安装(3)
- Linux系列(35) - 光盘yum源搭建(2)
- Linux系列(34) - yum源文件(1)
- Linux系列(33)- rpm命令管理之RPM包校验提取(5)
- Linux系列(32) - rpm命令管理之RPM查询(4)
- 创建Linux虚拟机(CentOS 7)
- vSphere 6.5虚拟机模板的创建和使用(windows与linux)
- 无人值守批量部署Linux操作系统
- 使用Kali Linux虚拟机破解WiFi密码的一波三折及详细操作步骤