update tw

This commit is contained in:
chai2010
2015-12-18 10:53:03 +08:00
parent 510c741a6f
commit c66a96ee52
106 changed files with 864 additions and 864 deletions

View File

@@ -1,6 +1,6 @@
## 8.8. 示例: 併髮的字典遍
## 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
@@ -84,7 +84,7 @@ $ ./du1 $HOME /usr /bin /etc
如果在運行的時候能夠讓我們知道處理進度的話想必更好。但是如果簡單地把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,7 +115,7 @@ 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循環。
現在程序會悠閒地爲我們打印更新流:
@@ -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
@@ -181,6 +181,6 @@ func dirents(dir string) []os.FileInfo {
這個版本比之前那個快了好幾倍,儘管其具體效率還是和你的運行環境,機器配置相關。
練習8.9: 編寫一個du工具每隔一段時間將root目下的目大小計算顯示齣來。
練習8.9: 編寫一個du工具每隔一段時間將root目下的目大小計算顯示齣來。