8.8 示例: 并发的目录遍历

知识点

  • 1.利用并发遍历并计算文件大小
  • 2.利用select,优化打印文件大小
  • 3.利用channel设置最大信号量,来防止打开文件过多

代码

func test_concurrent_directory()  {// Determine the initial directories.//------33333计算大小roots := []string{"/Users"}if len(roots) == 0 {roots = []string{"."}}// Traverse the file tree.fileSizes := make(chan int64)//go func() {//  for _, root := range roots {//      walkDir(root, fileSizes)//  }//  close(fileSizes)//}()//------44444计算大小优化/*因为磁盘系统并行限制,为了优化使用sync.WaitGroup (§8.5)来对仍旧活跃的walkDir调用进行计数,另一个goroutine会在计数器减为零的时候将fileSizes这个channel关闭*/var n sync.WaitGroupfor _, root := range roots {n.Add(1)go walkDir_group(root, &n, fileSizes)}go func() {n.Wait()close(fileSizes)}()// Print the results.var nfiles, nbytes int64//------11111累加大小打印//for size := range fileSizes {//  nfiles++//  nbytes += size//}//printDiskUsage(nfiles, nbytes)//------22222累加大小打印优化/*主goroutine现在使用了计时器来每500ms生成事件,然后用select语句来等待文件大小的消息来更新总大小数据,或者一个计时器的事件来打印当前的总大小数据*/// Print the results periodically.var tick <-chan time.Timetick = time.Tick(500 * time.Millisecond)
loop:for {select {case size, ok := <-fileSizes:if !ok {break loop // fileSizes was closed}nfiles++nbytes += sizecase <-tick:printDiskUsage(nfiles, nbytes)}}printDiskUsage(nfiles, nbytes) // final totals
}
/*练习 8.9: 编写一个du工具,每隔一段时间将root目录下的目录大小计算并显示出来
*/
func test_exerise89(timeS time.Duration, filep string)  {for {/*这一章,其实已经为我们写好了这个练习,只需要吧最优化的部分拿出来即可*/roots := []string{filep}if len(roots) == 0 {roots = []string{"."}}// Traverse the file tree.fileSizes := make(chan int64)var n sync.WaitGroupfor _, root := range roots {n.Add(1)go walkDir_group(root, &n, fileSizes)}go func() {n.Wait()close(fileSizes)}()var nfiles, nbytes int64for size := range fileSizes {nfiles++nbytes += size}//root目录下的目录大小计算并显示出来fmt.Println(filep + "  fileSizes")printDiskUsage(nfiles, nbytes)//每隔一段时间time.Sleep(timeS)}
}func printDiskUsage(nfiles, nbytes int64) {fmt.Printf("%d files  %.1f GB\n", nfiles, float64(nbytes)/1e9)
}
func walkDir(dir string, fileSizes chan<- int64) {for _, entry := range dirents(dir) {if entry.IsDir() {subdir := filepath.Join(dir, entry.Name())walkDir(subdir, fileSizes)} else {fileSizes <- entry.Size()}}
}
func walkDir_group(dir string, n *sync.WaitGroup, fileSizes chan<- int64) {defer n.Done()for _, entry := range dirents(dir) {if entry.IsDir() {n.Add(1)subdir := filepath.Join(dir, entry.Name())go walkDir_group(subdir, n, fileSizes)} else {fileSizes <- entry.Size()}}
}
/*由于这个程序在高峰期会创建成百上千的goroutine,我们需要修改dirents函数,用计数信号量来阻止他同时打开太多的文件
*/
// sema is a counting semaphore for limiting concurrency in dirents.
var sema = make(chan struct{}, 20)
func dirents(dir string) []os.FileInfo {sema <- struct{}{}        // acquire tokendefer func() { <-sema }() // release tokenentries, err := ioutil.ReadDir(dir)if err != nil {fmt.Fprintf(os.Stderr, "du1: %v\n", err)return nil}return entries
}

备注

《Go 语言圣经》

  • 学习记录所使用的GO版本是1.8
  • 学习记录所使用的编译器工具为GoLand
  • 学习记录所使用的系统环境为Mac os
  • 学习者有一定的C语言基础

代码仓库

Go 语言圣经 8.8 示例: 并发的目录遍历相关推荐

  1. Go语言圣经 - 第8章 Goroutines 和 Channels - 8.8 示例:并发的目录遍历

    第8章 Goroutines 和 Channels Go语言中的并发程序可以用两种手段来实现:goroutine 和 channel,其支持顺序通信进程,或被简称为CSP,CSP是一种并发编程模型,在 ...

  2. 《Go语言圣经》学习笔记 第八章 Groroutines和Channels

    <Go语言圣经>学习笔记 第八章 Groroutines和Channels 目录 Goroutines 实例:并发的Clock服务 实例:并发的Echo服务 Channels 并发的循环 ...

  3. 《Go语言圣经》学习笔记 第九章 基于共享变量的并发

    <Go语言圣经>学习笔记 第九章 基于共享变量的并发 目录 竞争条件 sync.Mutex互斥锁 syn.RWMutex读写锁 内存同步 syn.Once初始化 竞争条件检测 示例:并发的 ...

  4. Go基于共享变量的并发原理及实例 【Go语言圣经笔记】

    基于共享变量的并发 前一章我们介绍了一些使用goroutine和channel这样直接而自然的方式来实现并发的方法.然而这样做我们实际上回避了在写并发代码时必须处理的一些重要而且细微的问题(笔者注:一 ...

  5. 《Go语言圣经》学习笔记 第十一章 测试

    <Go语言圣经>学习笔记 第十一章 测试 目录 go test 测试函数 测试覆盖率 基准测试 剖析 示例函数 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. Go语 ...

  6. 《Go语言圣经》学习笔记 第十章 包和工具

    <Go语言圣经>学习笔记 第十章 包和工具 目录 包简介 导入路径 包声明 导入声明 包的匿名导入 包和命名 工具 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. G ...

  7. 《Go语言圣经》学习笔记 第一章 Go语言入门

    Go语言圣经学习笔记 第一章 Go语言入门 目录 Hello, World 命令行参数 查找重复的行 GIF动画 获取URL 并发获取多个URL Web服务 本章要点 注:学习<Go语言圣经&g ...

  8. 《Go语言圣经》学习笔记 第七章 接口

    <Go语言圣经>学习笔记 第七章 接口 目录 接口是合约 接口类型 实现接口的条件 flag.Value接口 接口值 sort.Interface接口 http.Handle接口 erro ...

  9. 《Go语言圣经》第一章 - 读书笔记

    <Go语言圣经>第一章 - 读书笔记 第一章 Go语言入门 01 Hello World 02 命令行参数 练习 练习1.1 练习1.2: 练习1.3: 03 查找重复的行 例子运行 du ...

最新文章

  1. es6 ... 添加属性_如何在10分钟内免费将HTTPS添加到您的网站,以及为什么您现在不止需要这样做......
  2. 你需要的不是重构,而是理清业务逻辑(转)
  3. UGUI 事件穿透规则
  4. Leetcode--213. 打家劫舍Ⅱ
  5. 运营商 sni 服务器,什么是服务器名称指示(SNI)
  6. 地铁人多不多可在线查询了 高德地图率先在北京上线新功能
  7. DSP5509项目之用FFT识别钢琴音调(5)之开始傅里叶变换
  8. go -生成pb文件 - 上
  9. mysql主从同步开启后的iptables的设定问题
  10. 【Github使用感触之一】使多文件多版本变得简单
  11. Thymeleaf 模板 js和css引入的方式
  12. windows安装和配置阿帕奇+PHP服务器
  13. 盖章php源码,模拟电子签章盖章效果的jQuery插件源码_jquery
  14. html 触摸屏页面,HTML5触摸屏touch事件使用实例1
  15. 【汇编】微机原理与接口技术课程设计
  16. Pytorch之Dataloader参数collate_fn研究
  17. (C语言编程)PTA里“三天打鱼两天晒网”
  18. 之江实验室与Science《科学》联合发布智能计算领域十大科学问题
  19. 数据库进阶·如何针对所有用户数据中没有的数据去加入随机的数据-蜻蜓Q系统用户没有头像如何加入头像数据-优雅草科技kir
  20. 西门子840d备份到u盘_840Dsl西门子数控系统怎么做备份和回装-工业支持中心-西门子中国...

热门文章

  1. iapp启动图代码_关于计算设备运行时间SCL代码的测试与说明
  2. 通信协议——以太网数据包协议格式
  3. Fama-French 三因子模型在A股市场的实证研究
  4. oracle24801错误,Access数据库通过ODBC导出到Oracle的两个小问题ora-24801\Ora-01401
  5. java计算机毕业设计高校校园社交网络源码+数据库+系统+lw文档+mybatis+运行部署
  6. Flink如何保证数据的一致性
  7. 北京注销公司需要什么材料?
  8. 电子音调发生器c语言编程,单片机电子音调发生器设计
  9. 分布式光纤测温火灾报警系统在向家坝某水电站的应用
  10. iOS开发68-iOS 如何让UIScrollView在手指离开后立即停止滑动