diff --git a/ch9/ch9-01.md b/ch9/ch9-01.md index 2c9e849..18be802 100644 --- a/ch9/ch9-01.md +++ b/ch9/ch9-01.md @@ -118,8 +118,8 @@ func Icon(name string) image.Image { return icons[name] } 下面是一個重寫了的銀行的例子,這個例子中balance變量被限製在了monitor goroutine中,名爲teller: +gopl.io/ch9/bank1 ```go -gopl.io/ch9/bank1 // Package bank provides a concurrency-safe bank with one account. package bank diff --git a/ch9/ch9-02.md b/ch9/ch9-02.md index 79e05f4..63de158 100644 --- a/ch9/ch9-02.md +++ b/ch9/ch9-02.md @@ -2,49 +2,49 @@ 在8.6節中,我們使用了一個buffered channel作爲一個計數信號量,來保證最多隻有20個goroutine會同時執行HTTP請求。同理,我們可以用一個容量隻有1的channel來保證最多隻有一個goroutine在同一時刻訪問一個共享變量。一個隻能爲1和0的信號量叫做二元信號量(binary semaphore)。 +gopl.io/ch9/bank2 ```go -gopl.io/ch9/bank2 var ( - sema = make(chan struct{}, 1) // a binary semaphore guarding balance - balance int + sema = make(chan struct{}, 1) // a binary semaphore guarding balance + balance int ) func Deposit(amount int) { - sema <- struct{}{} // acquire token - balance = balance + amount - <-sema // release token + sema <- struct{}{} // acquire token + balance = balance + amount + <-sema // release token } func Balance() int { - sema <- struct{}{} // acquire token - b := balance - <-sema // release token - return b + sema <- struct{}{} // acquire token + b := balance + <-sema // release token + return b } ``` 這種互斥很實用,而且被sync包里的Mutex類型直接支持。它的Lock方法能夠獲取到token(這里叫鎖),併且Unlock方法會釋放這個token: +gopl.io/ch9/bank3 ```go -gopl.io/ch9/bank3 import "sync" var ( - mu sync.Mutex // guards balance - balance int + mu sync.Mutex // guards balance + balance int ) func Deposit(amount int) { - mu.Lock() - balance = balance + amount - mu.Unlock() + mu.Lock() + balance = balance + amount + mu.Unlock() } func Balance() int { - mu.Lock() - b := balance - mu.Unlock() - return b + mu.Lock() + b := balance + mu.Unlock() + return b } ``` @@ -58,9 +58,9 @@ func Balance() int { ```go func Balance() int { - mu.Lock() - defer mu.Unlock() - return balance + mu.Lock() + defer mu.Unlock() + return balance } ``` @@ -73,12 +73,12 @@ func Balance() int { ```go // NOTE: not atomic! func Withdraw(amount int) bool { - Deposit(-amount) - if Balance() < 0 { - Deposit(amount) - return false // insufficient funds - } - return true + Deposit(-amount) + if Balance() < 0 { + Deposit(amount) + return false // insufficient funds + } + return true } ``` @@ -89,14 +89,14 @@ func Withdraw(amount int) bool { ```go // NOTE: incorrect! func Withdraw(amount int) bool { - mu.Lock() - defer mu.Unlock() - Deposit(-amount) - if Balance() < 0 { - Deposit(amount) - return false // insufficient funds - } - return true + mu.Lock() + defer mu.Unlock() + Deposit(-amount) + if Balance() < 0 { + Deposit(amount) + return false // insufficient funds + } + return true } ``` @@ -108,26 +108,26 @@ func Withdraw(amount int) bool { ```go func Withdraw(amount int) bool { - mu.Lock() - defer mu.Unlock() - deposit(-amount) - if balance < 0 { - deposit(amount) - return false // insufficient funds - } - return true + mu.Lock() + defer mu.Unlock() + deposit(-amount) + if balance < 0 { + deposit(amount) + return false // insufficient funds + } + return true } func Deposit(amount int) { - mu.Lock() - defer mu.Unlock() - deposit(amount) + mu.Lock() + defer mu.Unlock() + deposit(amount) } func Balance() int { - mu.Lock() - defer mu.Unlock() - return balance + mu.Lock() + defer mu.Unlock() + return balance } // This function requires that the lock be held. diff --git a/ch9/ch9-03.md b/ch9/ch9-03.md index 9452ea5..7cb4de4 100644 --- a/ch9/ch9-03.md +++ b/ch9/ch9-03.md @@ -8,9 +8,9 @@ var mu sync.RWMutex var balance int func Balance() int { - mu.RLock() // readers lock - defer mu.RUnlock() - return balance + mu.RLock() // readers lock + defer mu.RUnlock() + return balance } ``` diff --git a/ch9/ch9-04.md b/ch9/ch9-04.md index 958a614..85daae9 100644 --- a/ch9/ch9-04.md +++ b/ch9/ch9-04.md @@ -9,12 +9,12 @@ ```go var x, y int go func() { - x = 1 // A1 - fmt.Print("y:", y, " ") // A2 + x = 1 // A1 + fmt.Print("y:", y, " ") // A2 }() go func() { - y = 1 // B1 - fmt.Print("x:", x, " ") // B2 + y = 1 // B1 + fmt.Print("x:", x, " ") // B2 }() ``` diff --git a/ch9/ch9-07.md b/ch9/ch9-07.md index ce1846f..6b78b43 100644 --- a/ch9/ch9-07.md +++ b/ch9/ch9-07.md @@ -19,8 +19,8 @@ func httpGetBody(url string) (interface{}, error) { 下面是我們要設計的cache的第一個“草稿”: +gopl.io/ch9/memo1 ```go -gopl.io/ch9/memo1 // Package memo provides a concurrency-unsafe // memoization of a function of type Func. package memo @@ -153,8 +153,8 @@ memo.go的32行出現了兩次,説明有兩個goroutine在沒有同步榦預 最簡單的使cache併發安全的方式是使用基於監控的同步。隻要給Memo加上一個mutex,在Get的一開始獲取互斥鎖,return的時候釋放鎖,就可以讓cache的操作發生在臨界區內了: +gopl.io/ch9/memo2 ```go -gopl.io/ch9/memo2 type Memo struct { f Func mu sync.Mutex // guards cache @@ -181,8 +181,8 @@ func (memo *Memo) Get(key string) (value interface{}, err error) { 下一個Get的實現,調用Get的goroutine會兩次獲取鎖:査找階段獲取一次,如果査找沒有返迴任何內容,那麽進入更新階段會再次獲取。在這兩次獲取鎖的中間階段,其它goroutine可以隨意使用cache。 +gopl.io/ch9/memo3 ```go -gopl.io/ch9/memo3 func (memo *Memo) Get(key string) (value interface{}, err error) { memo.mu.Lock() res, ok := memo.cache[key] @@ -204,8 +204,8 @@ func (memo *Memo) Get(key string) (value interface{}, err error) { 理想情況下是應該避免掉多餘的工作的。而這種“避免”工作一般被稱爲duplicate suppression(重複抑製/避免)。下面版本的Memo每一個map元素都是指向一個條目的指針。每一個條目包含對函數f調用結果的內容緩存。與之前不同的是這次entry還包含了一個叫ready的channel。在條目的結果被設置之後,這個channel就會被關閉,以向其它goroutine廣播(§8.9)去讀取該條目內的結果是安全的了。 +gopl.io/ch9/memo4 ```go -gopl.io/ch9/memo4 type entry struct { res result ready chan struct{} // closed when res is ready @@ -275,8 +275,8 @@ type entry struct { 然而Memo類型現在包含了一個叫做requests的channel,Get的調用方用這個channel來和monitor goroutine來通信。requests channel中的元素類型是request。Get的調用方會把這個結構中的兩組key都填充好,實際上用這兩個變量來對函數進行緩存的。另一個叫response的channel會被拿來發送響應結果。這個channel隻會傳迴一個單獨的值。 +gopl.io/ch9/memo5 ```go -gopl.io/ch9/memo5 // A request is a message requesting that the Func be applied to key. type request struct { key string diff --git a/ch9/ch9-08-3.md b/ch9/ch9-08-3.md index a5e488c..6422ca8 100644 --- a/ch9/ch9-08-3.md +++ b/ch9/ch9-08-3.md @@ -7,8 +7,8 @@ Go的調度器使用了一個叫做GOMAXPROCS的變量來決定會有多少個 ```go for { - go fmt.Print(0) - fmt.Print(1) + go fmt.Print(0) + fmt.Print(1) } $ GOMAXPROCS=1 go run hacker-cliché.go