练习 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)
}

  

[日常] Go语言圣经-示例: 并发的目录遍历习题的更多相关文章

  1. [日常] Go语言圣经--示例: 并发的Clock服务习题

    练习 8.1: 修改clock2来支持传入参数作为端口号,然后写一个clockwall的程序,这个程序可以同时与多个clock服务器通信,从多服务器中读取时间,并且在一个表格中一次显示所有服务传回的结 ...

  2. [日常] Go语言圣经--示例: 并发的Echo服务

    最简单的回声服务器: package main import ( "io" "net" "log" ) func main() { list ...

  3. [日常] Go语言圣经--包和文件-导入包习题

    1.每个包都有一个全局唯一的导入路径 2.按照惯例,一个包的名字和包的导入路径的最后一个字段相同 练习 2.2: 写一个通用的单位转换程序,用类似cf程序的方式从命令行读取参数,如果缺省的话则是从标准 ...

  4. [日常] Go语言圣经--包和文件-包初始化习题

    1.解决包级变量的依赖顺序,然后按照包级变量声明出现的顺序依次初始化 2.包中含有多个.go源文件,它们将按照发给编译器的顺序进行初始化 3.init初始化函数,在每个文件中的init初始化函数,在程 ...

  5. [日常] GO语言圣经-并发获取多个URL

    go语言圣经-并发获取多个URL 1.GO最新奇的特性就是对并发编程的支持,goroutine和channel 2.goroutine是一种函数的并发执行方式,而channel是用来在goroutin ...

  6. [日常] Go语言圣经前言

    https://books.studygolang.com/gopl-zh/ go语言圣经 1.Go语言有时候被描述为“C类似语言”,或者是“21世纪的C语言”. 2.Go语言中和并发编程相关的特性是 ...

  7. [日常] go语言圣经-声明,变量,赋值,类型,包和文件习题

    go语言圣经-声明1.四种类型的声明语句:var.const.type和func,分别对应变量.常量.类型和函数实体对象的声明2.包一级声明语句声明的名字可在整个包对应的每个源文件中访问,局部声明的名 ...

  8. [日常] Go语言圣经-WEB服务与习题

    Go语言圣经-web服务 1.Web服务程序,标准库里的方法已经帮我们完成了大量工作 2.main函数将所有发送到/路径下的请求和handler函数关联起来,/开头的请求其实就是所有发送到当前站点上的 ...

  9. [日常] Go语言圣经--接口约定习题

    Go语言圣经-接口1.接口类型是对其它类型行为的抽象和概括2.Go语言中接口类型的独特之处在于它是满足隐式实现的3.Go语言中还存在着另外一种类型:接口类型.接口类型是一种抽象的类型4.一个类型可以自 ...

随机推荐

  1. consul集群docker版本脚本

    https://blog.csdn.net/fenglailea/article/details/79098246 docker run -d --name node1 -e 'CONSUL_LOCA ...

  2. spring项目读取配置的demo

    背景 读取配置是基础能力,研发这个模式不错,可以从不同配置中读取数据,如下图: 可以根据不同分类的文件来管理配置,然后统一在conf中配置哪些文件 package com.jwen.platform. ...

  3. Django:全文检索功能可参考博客

    https://blog.csdn.net/AC_hell/article/details/52875927 https://www.zmrenwu.com/courses/django-blog-t ...

  4. sql解决避免除以零的错误

    在实际项目中,我们可能会遇到求百分比,比值等带除法的sql语句.这时,我们也许会遇到分母为零的情况.下面给出我总结的一些方法: 1. 用NULLIF函数: 首先说一下NULLIF函数的语法: NULL ...

  5. .net core中Quartz的使用

    原来工作中有用到定时任务Quartz,不过是在MVC项目中,现在net core项目中也要用到,就开始改版.中间发现在网上的教程只有执行定时计划的过程,却很少有人写注册的过程,觉得有点略坑.所以写此文 ...

  6. 【牛客OI赛制测试赛3】 毒瘤xor

    牛客OI赛制测试赛3 毒瘤xor 传送门 题面,水表者自重 Solution 前缀和简单题(挖坑待补) 代码实现 #include<stdio.h> #define int long lo ...

  7. ssh登录时在参数中加入密码的解决方案

    在使用ssh登录远程服务器的时候,在执行完ssh user@ip后,要输入登录密码,有时候登录密码记不住,这样以来Ian带来的很多的麻烦,有没有一种在ssh的参数中直接加入密码的方法呢?查看ssh的帮 ...

  8. redo log文件格式描述

  9. [Leetcode]315.计算右侧小于当前元素的个数 (6种方法)

    链接 给定一个整数数组 nums,按要求返回一个新数组 counts.数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量. 示例: 输 ...

  10. 安装MySQL-python时报错

    (py27) [root@test SimpletourDevops]# pip install MySQL-python DEPRECATION: Python 2.7 will reach the ...