make loop

This commit is contained in:
chai2010
2015-12-26 20:05:30 +08:00
parent 82ec0c025d
commit e15e88dad7
74 changed files with 207 additions and 207 deletions

View File

@@ -1,14 +1,14 @@
## 8.9. 併發的退
## 8.9. 併發的退
有時候我們需要通知goroutine停止它正在榦的事情比如一個正在執行計算的web服務然而它的客戶端已經斷開了和服務端的連接。
Go語言併沒有提供在一個goroutine中終止另一個goroutine的方法由於這樣會導致goroutine之間的共享變量落在未定義的狀態上。在8.7節中的rocket launch程序中我們往名字叫abort的channel里發送了一個簡單的值在countdown的goroutine中會把這個值理解爲自己的退信號。但是如果我們想要退兩個或者任意多個goroutine怎麽辦呢
Go語言併沒有提供在一個goroutine中終止另一個goroutine的方法由於這樣會導致goroutine之間的共享變量落在未定義的狀態上。在8.7節中的rocket launch程序中我們往名字叫abort的channel里發送了一個簡單的值在countdown的goroutine中會把這個值理解爲自己的退信號。但是如果我們想要退兩個或者任意多個goroutine怎麽辦呢
一種可能的手段是向abort的channel里發送和goroutine數目一樣多的事件來退它們。如果這些goroutine中已經有一些自己退那麽會導致我們的channel里的事件數比goroutine還多這樣導致我們的發送直接被阻塞。另一方面如果這些goroutine又生成了其它的goroutine我們的channel里的數目又太少了所以有些goroutine可能會無法接收到退消息。一般情況下我們是很難知道在某一個時刻具體有多少個goroutine在運行着的。另外當一個goroutine從abort channel中接收到一個值的時候他會消費掉這個值這樣其它的goroutine就沒法看到這條信息。爲了能夠達到我們退goroutine的目的我們需要更靠譜的策略來通過一個channel把消息廣播這樣goroutine們能夠看到這條事件消息併且在事件完成之後可以知道這件事已經發生過了。
一種可能的手段是向abort的channel里發送和goroutine數目一樣多的事件來退它們。如果這些goroutine中已經有一些自己退那麽會導致我們的channel里的事件數比goroutine還多這樣導致我們的發送直接被阻塞。另一方面如果這些goroutine又生成了其它的goroutine我們的channel里的數目又太少了所以有些goroutine可能會無法接收到退消息。一般情況下我們是很難知道在某一個時刻具體有多少個goroutine在運行着的。另外當一個goroutine從abort channel中接收到一個值的時候他會消費掉這個值這樣其它的goroutine就沒法看到這條信息。爲了能夠達到我們退goroutine的目的我們需要更靠譜的策略來通過一個channel把消息廣播這樣goroutine們能夠看到這條事件消息併且在事件完成之後可以知道這件事已經發生過了。
迴憶一下我們關閉了一個channel併且被消費掉了所有已發送的值操作channel之後的代碼可以立卽被執行併且會産生零值。我們可以將這個機製擴展一下來作爲我們的廣播機製不要向channel發送值而是用關閉一個channel來進行廣播。
隻要一些小脩改,我們就可以把退邏輯加入到前一節的du程序。首先我們創建一個退的channel這個channel不會向其中發送任何值但其所在的閉包內要寫明程序需要退。我們同時還定義了一個工具函數cancelled這個函數在被調用的時候會輪詢退狀態。
隻要一些小脩改,我們就可以把退邏輯加入到前一節的du程序。首先我們創建一個退的channel這個channel不會向其中發送任何值但其所在的閉包內要寫明程序需要退。我們同時還定義了一個工具函數cancelled這個函數在被調用的時候會輪詢退狀態。
```go
gopl.io/ch8/du4
@@ -24,7 +24,7 @@ func cancelled() bool {
}
```
下面我們創建一個從標準輸入流中讀取內容的goroutine這是一個比較典型的連接到終端的程序。每當有輸入被讀到(比如用戶按了迴車鍵)這個goroutine就會把取消消息通過關閉done的channel廣播去。
下面我們創建一個從標準輸入流中讀取內容的goroutine這是一個比較典型的連接到終端的程序。每當有輸入被讀到(比如用戶按了迴車鍵)這個goroutine就會把取消消息通過關閉done的channel廣播去。
```go
// Cancel traversal when input is detected.
@@ -82,7 +82,7 @@ func dirents(dir string) []os.FileInfo {
}
```
現在當取消發生時所有後颱的goroutine都會迅速停止併且主函數會返迴。當然當主函數返迴時一個程序會退,而我們又無法在主函數退的時候確認其已經釋放了所有的資源(譯註:因爲程序都退了,你的代碼都沒法執行了)。這里有一個方便的竅門我們可以一用取代掉直接從主函數返迴我們調用一個panic然後runtime會把每一個goroutine的棧dump下來。如果main goroutine是唯一一個剩下的goroutine的話他會清理掉自己的一切資源。但是如果還有其它的goroutine沒有退他們可能沒辦法被正確地取消掉也有可能被取消但是取消操作會很花時間所以這里的一個調研還是很有必要的。我們用panic來穫取到足夠的信息來驗證我們上面的判斷看看最終到底是什麽樣的情況。
現在當取消發生時所有後颱的goroutine都會迅速停止併且主函數會返迴。當然當主函數返迴時一個程序會退,而我們又無法在主函數退的時候確認其已經釋放了所有的資源(譯註:因爲程序都退了,你的代碼都沒法執行了)。這里有一個方便的竅門我們可以一用取代掉直接從主函數返迴我們調用一個panic然後runtime會把每一個goroutine的棧dump下來。如果main goroutine是唯一一個剩下的goroutine的話他會清理掉自己的一切資源。但是如果還有其它的goroutine沒有退他們可能沒辦法被正確地取消掉也有可能被取消但是取消操作會很花時間所以這里的一個調研還是很有必要的。我們用panic來穫取到足夠的信息來驗證我們上面的判斷看看最終到底是什麽樣的情況。
練習8.10: HTTP請求可能會因http.Request結構體中Cancel channel的關閉而取消。脩改8.6節中的web crawler來支持取消http請求。