This commit is contained in:
chai2010
2016-01-18 11:14:19 +08:00
parent a91355f5f1
commit 884ada9cd0
20 changed files with 116 additions and 92 deletions

View File

@@ -147,7 +147,7 @@ $ ./netcat1
$ killall clock2
```
練習8.1: 脩改clock2來支持傳入參數作爲端口號然後寫一個clockwall的程序這個程序可以同時與多個clock服務器通信從多服務器中讀取時間併且在一個表格中一次顯示所有服務傳迴的結果類似於你在某些辦公室里看到的時鐘牆。如果你有地理學上分布式的服務器可以用的話讓這些服務器跑在不同的機器上面或者在同一台機器上跑多個不同的實例這些實例監聽不同的端口假裝自己在不同的時區。像下面這樣
**練習 8.1** 脩改clock2來支持傳入參數作爲端口號然後寫一個clockwall的程序這個程序可以同時與多個clock服務器通信從多服務器中讀取時間併且在一個表格中一次顯示所有服務傳迴的結果類似於你在某些辦公室里看到的時鐘牆。如果你有地理學上分布式的服務器可以用的話讓這些服務器跑在不同的機器上面或者在同一台機器上跑多個不同的實例這些實例監聽不同的端口假裝自己在不同的時區。像下面這樣
```
$ TZ=US/Eastern ./clock2 -port 8010 &
@@ -156,4 +156,4 @@ $ TZ=Europe/London ./clock2 -port 8030 &
$ clockwall NewYork=localhost:8010 Tokyo=localhost:8020 London=localhost:8030
```
練習8.2: 實現一個併發FTP服務器。服務器應該解析客戶端來的一些命令比如cd命令來切換目録ls來列出目録內文件get和send來傳輸文件close來關閉連接。你可以用標準的ftp命令來作爲客戶端或者也可以自己實現一個。
**練習 8.2** 實現一個併發FTP服務器。服務器應該解析客戶端來的一些命令比如cd命令來切換目録ls來列出目録內文件get和send來傳輸文件close來關閉連接。你可以用標準的ftp命令來作爲客戶端或者也可以自己實現一個。

View File

@@ -184,6 +184,6 @@ sizes channel攜帶了每一個文件的大小到main goroutine在main gorout
![](../images/ch8-05.png)
練習8.4: 脩改reverb2服務器在每一個連接中使用sync.WaitGroup來計數活躍的echo goroutine。當計數減爲零時關閉TCP連接的寫入像練習8.3中一樣。驗證一下你的脩改版netcat3客戶端會一直等待所有的併發“喊叫”完成卽使是在標準輸入流已經關閉的情況下。
**練習 8.4** 脩改reverb2服務器在每一個連接中使用sync.WaitGroup來計數活躍的echo goroutine。當計數減爲零時關閉TCP連接的寫入像練習8.3中一樣。驗證一下你的脩改版netcat3客戶端會一直等待所有的併發“喊叫”完成卽使是在標準輸入流已經關閉的情況下。
練習8.5: 使用一個已有的CPU綁定的順序程序比如在3.3節中我們寫的Mandelbrot程序或者3.2節中的3-D surface計算程序併將他們的主循環改爲併發形式使用channel來進行通信。在多核計算機上這個程序得到了多少速度上的改進使用多少個goroutine是最合適的呢
**練習 8.5** 使用一個已有的CPU綁定的順序程序比如在3.3節中我們寫的Mandelbrot程序或者3.2節中的3-D surface計算程序併將他們的主循環改爲併發形式使用channel來進行通信。在多核計算機上這個程序得到了多少速度上的改進使用多少個goroutine是最合適的呢

View File

@@ -159,11 +159,10 @@ seen這個map被限定在main goroutine中也就是説這個map隻能在main
crawl函數爬到的鏈接在一個專有的goroutine中被發送到worklist中來避免死鎖。爲了節省空間這個例子的終止問題我們先不進行詳細闡述了。
練習8.6: 爲併發爬蟲增加深度限製。也就是説如果用戶設置了depth=3那麽隻有從首頁跳轉三次以內能夠跳到的頁面才能被抓取到。
**練習 8.6** 爲併發爬蟲增加深度限製。也就是説如果用戶設置了depth=3那麽隻有從首頁跳轉三次以內能夠跳到的頁面才能被抓取到。
練習8.7: 完成一個併發程序來創建一個線上網站的本地鏡像,把該站點的所有可達的頁面都抓取到本地硬盤。爲了省事,我們這里可以隻取出現在該域下的所有頁面(比如golang.org結尾譯註外鏈的應該就不算了。)當然了,出現在頁面里的鏈接你也需要進行一些處理,使其能夠在你的鏡像站點上進行跳轉,而不是指向原始的鏈接。
**練習 8.7** 完成一個併發程序來創建一個線上網站的本地鏡像,把該站點的所有可達的頁面都抓取到本地硬盤。爲了省事,我們這里可以隻取出現在該域下的所有頁面(比如golang.org結尾譯註外鏈的應該就不算了。)當然了,出現在頁面里的鏈接你也需要進行一些處理,使其能夠在你的鏡像站點上進行跳轉,而不是指向原始的鏈接。
譯註:
拓展閲讀
http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/
**譯註:**
拓展閲讀 [Handling 1 Million Requests per Minute with Go](http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/)。

View File

@@ -131,4 +131,4 @@ channel的零值是nil。也許會讓你覺得比較奇怪nil的channel有時
這使得我們可以用nil來激活或者禁用case來達成處理其它輸入或輸出事件時超時和取消的邏輯。我們會在下一節中看到一個例子。
練習8.8: 使用select來改造8.3節中的echo服務器爲其增加超時這樣服務器可以在客戶端10秒中沒有任何喊話時自動斷開連接。
**練習 8.8** 使用select來改造8.3節中的echo服務器爲其增加超時這樣服務器可以在客戶端10秒中沒有任何喊話時自動斷開連接。

View File

@@ -181,4 +181,4 @@ func dirents(dir string) []os.FileInfo {
這個版本比之前那個快了好幾倍,盡管其具體效率還是和你的運行環境,機器配置相關。
練習8.9: 編寫一個du工具每隔一段時間將root目録下的目録大小計算併顯示出來。
**練習 8.9** 編寫一個du工具每隔一段時間將root目録下的目録大小計算併顯示出來。

View File

@@ -83,8 +83,6 @@ func dirents(dir string) []os.FileInfo {
現在當取消發生時所有後台的goroutine都會迅速停止併且主函數會返迴。當然當主函數返迴時一個程序會退出而我們又無法在主函數退出的時候確認其已經釋放了所有的資源(譯註:因爲程序都退出了,你的代碼都沒法執行了)。這里有一個方便的竅門我們可以一用取代掉直接從主函數返迴我們調用一個panic然後runtime會把每一個goroutine的棧dump下來。如果main goroutine是唯一一個剩下的goroutine的話他會清理掉自己的一切資源。但是如果還有其它的goroutine沒有退出他們可能沒辦法被正確地取消掉也有可能被取消但是取消操作會很花時間所以這里的一個調研還是很有必要的。我們用panic來獲取到足夠的信息來驗證我們上面的判斷看看最終到底是什麽樣的情況。
練習8.10: HTTP請求可能會因http.Request結構體中Cancel channel的關閉而取消。脩改8.6節中的web crawler來支持取消http請求。
**練習 8.10** HTTP請求可能會因http.Request結構體中Cancel channel的關閉而取消。脩改8.6節中的web crawler來支持取消http請求。提示http.Get併沒有提供方便地定製一個請求的方法。你可以用http.NewRequest來取而代之設置它的Cancel字段然後用http.DefaultClient.Do(req)來進行這個http請求。
提示: http.Get併沒有提供方便地定製一個請求的方法。你可以用http.NewRequest來取而代之設置它的Cancel字段然後用http.DefaultClient.Do(req)來進行這個http請求。
練習8.11:緊接着8.4.4中的mirroredQuery流程實現一個併發請求url的fetch的變種。當第一個請求返迴時直接取消其它的請求。
**練習 8.11** 緊接着8.4.4中的mirroredQuery流程實現一個併發請求url的fetch的變種。當第一個請求返迴時直接取消其它的請求。

View File

@@ -114,7 +114,10 @@ You are 127.0.0.1:64216 127.0.0.1:64216 has arrived
當與n個客戶端保持聊天session時這個程序會有2n+2個併發的goroutine然而這個程序卻併不需要顯式的鎖(§9.2)。clients這個map被限製在了一個獨立的goroutine中broadcaster所以它不能被併發地訪問。多個goroutine共享的變量隻有這些channel和net.Conn的實例兩個東西都是併發安全的。我們會在下一章中更多地解決約束併發安全以及goroutine中共享變量的含義。
練習8.12: 使broadcaster能夠將arrival事件通知當前所有的客戶端。爲了達成這個目的你需要有一個客戶端的集合併且在entering和leaving的channel中記録客戶端的名字。
練習8.13: 使聊天服務器能夠斷開空閒的客戶端連接比如最近五分鐘之後沒有發送任何消息的那些客戶端。提示可以在其它goroutine中調用conn.Close()來解除Read調用就像input.Scanner()所做的那樣。
練習8.14: 脩改聊天服務器的網絡協議這樣每一個客戶端就可以在entering時可以提供它們的名字。將消息前綴由之前的網絡地址改爲這個名字
練習8.15: 如果一個客戶端沒有及時地讀取數據可能會導致所有的客戶端被阻塞。脩改broadcaster來跳過一條消息而不是等待這個客戶端一直到其準備好寫。或者爲每一個客戶端的消息發出channel建立緩衝區這樣大部分的消息便不會被丟掉broadcaster應該用一個非阻塞的send向這個channel中發消息。
**練習 8.12** 使broadcaster能夠將arrival事件通知當前所有的客戶端。爲了達成這個目的你需要有一個客戶端的集合併且在entering和leaving的channel中記録客戶端的名字。
**練習 8.13** 使聊天服務器能夠斷開空閒的客戶端連接比如最近五分鐘之後沒有發送任何消息的那些客戶端。提示可以在其它goroutine中調用conn.Close()來解除Read調用就像input.Scanner()所做的那樣
**練習 8.14** 脩改聊天服務器的網絡協議這樣每一個客戶端就可以在entering時可以提供它們的名字。將消息前綴由之前的網絡地址改爲這個名字。
**練習 8.15** 如果一個客戶端沒有及時地讀取數據可能會導致所有的客戶端被阻塞。脩改broadcaster來跳過一條消息而不是等待這個客戶端一直到其準備好寫。或者爲每一個客戶端的消息發出channel建立緩衝區這樣大部分的消息便不會被丟掉broadcaster應該用一個非阻塞的send向這個channel中發消息。