mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 11:44:20 +08:00
make
This commit is contained in:
@@ -82,7 +82,7 @@ func crawl(url string) []string {
|
||||
}
|
||||
```
|
||||
|
||||
第二个问题是这个程序永远都不会终止,即使它已经爬到了所有初始链接衍生出的链接。(当然,除非你慎重地选择了合适的初始化URL或者已经实现了练习8.6中的深度限制,你应该还没有意识到这个问题)。为了使这个程序能够终止,我们需要在worklist为空或者没有crawl的goroutine在运行时退出主循环。
|
||||
第二個問題是這個程序永遠都不會終止,卽使它已經爬到了所有初始鏈接衍生齣的鏈接。(噹然,除非你慎重地選擇了閤適的初始化URL或者已經實現了練習8.6中的深度限製,你應該還沒有意識到這個問題)。爲了使這個程序能夠終止,我們需要在worklist爲空或者沒有crawl的goroutine在運行時退齣主循環。
|
||||
|
||||
|
||||
```go
|
||||
|
||||
@@ -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类型的slice,os.FileInfo类型也是os.Stat这个函数的返回值。对每一个子目录而言,walkDir会递归地调用其自身,并且会对每一个文件也递归调用。walkDir函数会向fileSizes这个channel发送一条消息。这条消息包含了文件的字节大小。
|
||||
ioutil.ReadDir函數會返迴一個os.FileInfo類型的slice,os.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目彔下的目彔大小計算併顯示齣來。
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user