This commit is contained in:
chai2010
2015-12-11 17:19:15 +08:00
parent fd6262f241
commit 643409dd27
4 changed files with 44 additions and 44 deletions

View File

@@ -82,7 +82,7 @@ func crawl(url string) []string {
}
```
第二个问题是这个程序永都不会终止,使它已爬到了所有初始接衍生出的链接。(然,除非你慎重地选择了合适的初始化URL或者已经实现了练习8.6中的深度限,你应该还没有意识到这个问题)。了使这个程序能够终止,我需要在worklist空或者有crawl的goroutine在运行时退出主循
第二個問題是這個程序永都不會終止,使它已爬到了所有初始接衍生齣的鏈接。(然,除非你慎重地選擇了閤適的初始化URL或者已經實現了練習8.6中的深度限,你應該還沒有意識到這個問題)。了使這個程序能夠終止,我需要在worklist空或者有crawl的goroutine在運行時退齣主循
```go

View File

@@ -1,6 +1,6 @@
## 8.8. 示例: 併髮的字典遍歷
在本小中,我们会创建一程序生成指定目的硬使用情况报告,这个程序和Unix的du工具比相似。大多工作用下面这个walkDir函数来完成,这个函数使用dirents函数来枚举一个目录下的所有入口。
在本小中,我們會創建一程序生成指定目的硬使用情況報告,這個程序和Unix的du工具比相似。大多工作用下麫這個walkDir函數來完成,這個函數使用dirents函數來枚舉一個目彔下的所有入口。
```go
gopl.io/ch8/du1
@@ -28,9 +28,9 @@ func dirents(dir string) []os.FileInfo {
}
```
ioutil.ReadDir函数会返回一个os.FileInfo型的sliceos.FileInfo型也是os.Stat这个函数的返值。每一子目而言walkDir会递归地调用其自身,并且会对每一文件也递归调用。walkDir函数会向fileSizes这个channel送一消息。这条消息包含了文件的字大小。
ioutil.ReadDir函數會返迴一個os.FileInfo型的sliceos.FileInfo型也是os.Stat這個函數的返值。每一子目而言walkDir會遞歸地調用其自身,併且會對每一文件也遞歸調用。walkDir函數會曏fileSizes這個channel送一消息。這條消息包含了文件的字大小。
的主函,用了两个goroutine。后台的goroutine用walkDir来遍历命令行给出的每一个路径并最终关闭fileSizes这个channel。主goroutine会对其从channel中接收到的文件大小进行累加,并输出其和。
的主函,用了兩個goroutine。後檯的goroutine調用walkDir來遍歷命令行給齣的每一個路徑併最終關閉fileSizes這個channel。主goroutine會對其從channel中接收到的文件大小進行纍加,併輸齣其和。
```go
@@ -75,16 +75,16 @@ func printDiskUsage(nfiles, nbytes int64) {
}
```
这个程序在打印其果之前卡住很长时间
這個程序在打印其果之前卡住很長時間
```
$ go build gopl.io/ch8/du1
$ ./du1 $HOME /usr /bin /etc
213201 files 62.7 GB
```
如果在行的候能够让我们知道处理进度的想必更好。但是,如果简单地把printDiskUsage函数调用移到循环里会导致其打印成百上千的输出
如果在行的候能夠讓我們知道處理進度的想必更好。但是,如果簡單地把printDiskUsage函數調用移到循環裡會導緻其打印成百上韆的輸齣
面这个du的变种会间歇打印容,不过只有在调用时提供了-v的flag才会显示程序度信息。在roots目上循环的后台goroutine在这里保持不。主goroutine在使用了计时器来每500ms生成事件用select语句来等待文件大小的消息更新大小数据,或者一个计时器的事件打印前的大小数据。如果-v的flag在运行时没有传入的tick这个channel保持nil这样在select的case也就相当于被禁用了。
麫這個du的變種會間歇打印容,不過隻有在調用時提供了-v的flag纔會顯示程序度信息。在roots目上循環的後檯goroutine在這裡保持不。主goroutine在使用了計時器來每500ms生成事件用select語句來等待文件大小的消息更新大小數據,或者一個計時器的事件打印前的大小數據。如果-v的flag在運行時沒有傳入的tick這個channel保持nil這樣在select的case也就相噹於被禁用了。
```go
gopl.io/ch8/du2
@@ -115,9 +115,9 @@ loop:
printDiskUsage(nfiles, nbytes) // final totals
}
```
于我们的程序不再使用range循,第一select的case必须显式地判fileSizes的channel是不是已经被关闭了,这里可以用到channel接收的二值形式。如果channel已经被关闭了的,程序直接退出循环。这里的break句用到了标签break这样可以同时终结select和for两个循环;如果有用标签就break的话只会退出内层的select循,而外的for循环会使之入下一select循
於我們的程序不再使用range循,第一select的case必須顯式地判fileSizes的channel是不是已經被關閉了,這裡可以用到channel接收的二值形式。如果channel已經被關閉了的,程序直接退齣循環。這裡的break句用到了標籤break這樣可以衕時終結select和for兩個循環;如果有用標籤就break的話隻會退齣內層的select循,而外的for循環會使之入下一select循
在程序会悠闲地为我们打印更新流:
在程序會悠閒地爲我們打印更新流:
```
$ go build gopl.io/ch8/du2
@@ -130,7 +130,7 @@ $ ./du2 -v $HOME /usr /bin /etc
213201 files 62.7 GB
```
然而这个程序还是会花上很长时间才会结束。无法对walkDir做行化处理没什么别的原因,非是因为磁盘系统并行限。下面这个第三版本的du会对每一walkDir的调用创建一新的goroutine。它使用sync.WaitGroup (§8.5)来对仍旧活跃的walkDir调用进行计数,另一goroutine会在计数器减为零的时候将fileSizes这个channel关闭
然而這個程序還是會花上很長時間纔會結束。無法對walkDir做行化處理沒什麽彆的原因,非是因爲磁盤繫統併行限。下麫這個第三版本的du會對每一walkDir的調用創建一新的goroutine。它使用sync.WaitGroup (§8.5)來對仍舊活躍的walkDir調用進行計數,另一goroutine會在計數器減爲零的時候將fileSizes這個channel關閉
```go
gopl.io/ch8/du3
@@ -164,7 +164,7 @@ func walkDir(dir string, n *sync.WaitGroup, fileSizes chan<- int64) {
}
```
于这个程序在高峰期会创建成百上的goroutine需要改dirents函,用计数信号量来阻止他同时打开太多的文件,就像我在8.7中的并发爬虫一样
於這個程序在高峯期會創建成百上的goroutine需要改dirents函,用計數信號量來阻止他衕時打開太多的文件,就像我在8.7中的併發爬蟲一樣
```go
@@ -179,8 +179,8 @@ func dirents(dir string) []os.FileInfo {
```
这个版本比之前那快了好倍,管其具效率是和你的运行环境,器配置相
這個版本比之前那快了好倍,管其具效率是和你的運行環境,器配置相
练习8.9: 编写一个du工具每隔一段时间将root目下的目大小计算并显示出来
練習8.9: 編寫一個du工具每隔一段時間將root目下的目大小計算併顯示齣來