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