From 86650d2d26147eda75bfc714c475d209ff295da5 Mon Sep 17 00:00:00 2001 From: chai2010 Date: Mon, 18 Jan 2016 17:51:17 +0800 Subject: [PATCH] ch9-7: fmt code --- ch9/ch9-07.md | 234 +++++++++++++++++++++++++------------------------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/ch9/ch9-07.md b/ch9/ch9-07.md index 567e3ce..ce1846f 100644 --- a/ch9/ch9-07.md +++ b/ch9/ch9-07.md @@ -6,12 +6,12 @@ ```go func httpGetBody(url string) (interface{}, error) { - resp, err := http.Get(url) - if err != nil { - return nil, err - } - defer resp.Body.Close() - return ioutil.ReadAll(resp.Body) + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return ioutil.ReadAll(resp.Body) } ``` @@ -27,30 +27,30 @@ package memo // A Memo caches the results of calling a Func. type Memo struct { - f Func - cache map[string]result + f Func + cache map[string]result } // Func is the type of the function to memoize. type Func func(key string) (interface{}, error) type result struct { - value interface{} - err error + value interface{} + err error } func New(f Func) *Memo { - return &Memo{f: f, cache: make(map[string]result)} + return &Memo{f: f, cache: make(map[string]result)} } // NOTE: not concurrency-safe! func (memo *Memo) Get(key string) (interface{}, error) { - res, ok := memo.cache[key] - if !ok { - res.value, res.err = memo.f(key) - memo.cache[key] = res - } - return res.value, res.err + res, ok := memo.cache[key] + if !ok { + res.value, res.err = memo.f(key) + memo.cache[key] = res + } + return res.value, res.err } ``` @@ -61,13 +61,13 @@ Memo實例會記録需要緩存的函數f(類型爲Func),以及緩存內容( ```go m := memo.New(httpGetBody) for url := range incomingURLs() { - start := time.Now() - value, err := m.Get(url) - if err != nil { - log.Print(err) - } - fmt.Printf("%s, %s, %d bytes\n", - url, time.Since(start), len(value.([]byte))) + start := time.Now() + value, err := m.Get(url) + if err != nil { + log.Print(err) + } + fmt.Printf("%s, %s, %d bytes\n", + url, time.Since(start), len(value.([]byte))) } ``` @@ -97,17 +97,17 @@ ok gopl.io/ch9/memo1 1.257s m := memo.New(httpGetBody) var n sync.WaitGroup for url := range incomingURLs() { - n.Add(1) - go func(url string) { - start := time.Now() - value, err := m.Get(url) - if err != nil { - log.Print(err) - } - fmt.Printf("%s, %s, %d bytes\n", - url, time.Since(start), len(value.([]byte))) - n.Done() - }(url) + n.Add(1) + go func(url string) { + start := time.Now() + value, err := m.Get(url) + if err != nil { + log.Print(err) + } + fmt.Printf("%s, %s, %d bytes\n", + url, time.Since(start), len(value.([]byte))) + n.Done() + }(url) } n.Wait() ``` @@ -156,24 +156,24 @@ memo.go的32行出現了兩次,説明有兩個goroutine在沒有同步榦預 ```go gopl.io/ch9/memo2 type Memo struct { - f Func - mu sync.Mutex // guards cache - cache map[string]result + f Func + mu sync.Mutex // guards cache + cache map[string]result } // Get is concurrency-safe. func (memo *Memo) Get(key string) (value interface{}, err error) { - res, ok := memo.cache[key] if!ok{ - res.value, res.err = memo.f(key) - memo.cache[key] = res - memo.mu.Lock() - res, ok := memo.cache[key] - if !ok { - res.value, res.err = memo.f(key) - memo.cache[key] = res - } - memo.mu.Unlock() - return res.value, res.err + res, ok := memo.cache[key] if!ok{ + res.value, res.err = memo.f(key) + memo.cache[key] = res + memo.mu.Lock() + res, ok := memo.cache[key] + if !ok { + res.value, res.err = memo.f(key) + memo.cache[key] = res + } + memo.mu.Unlock() + return res.value, res.err } ``` @@ -184,19 +184,19 @@ func (memo *Memo) Get(key string) (value interface{}, err error) { ```go gopl.io/ch9/memo3 func (memo *Memo) Get(key string) (value interface{}, err error) { - memo.mu.Lock() - res, ok := memo.cache[key] - memo.mu.Unlock() - if !ok { - res.value, res.err = memo.f(key) + memo.mu.Lock() + res, ok := memo.cache[key] + memo.mu.Unlock() + if !ok { + res.value, res.err = memo.f(key) - // Between the two critical sections, several goroutines - // may race to compute f(key) and update the map. - memo.mu.Lock() - memo.cache[key] = res - memo.mu.Unlock() - } - return res.value, res.err + // Between the two critical sections, several goroutines + // may race to compute f(key) and update the map. + memo.mu.Lock() + memo.cache[key] = res + memo.mu.Unlock() + } + return res.value, res.err } ``` @@ -207,41 +207,41 @@ func (memo *Memo) Get(key string) (value interface{}, err error) { ```go gopl.io/ch9/memo4 type entry struct { - res result - ready chan struct{} // closed when res is ready + res result + ready chan struct{} // closed when res is ready } func New(f Func) *Memo { - return &Memo{f: f, cache: make(map[string]*entry)} + return &Memo{f: f, cache: make(map[string]*entry)} } type Memo struct { - f Func - mu sync.Mutex // guards cache - cache map[string]*entry + f Func + mu sync.Mutex // guards cache + cache map[string]*entry } func (memo *Memo) Get(key string) (value interface{}, err error) { - memo.mu.Lock() - e := memo.cache[key] - if e == nil { - // This is the first request for this key. - // This goroutine becomes responsible for computing - // the value and broadcasting the ready condition. - e = &entry{ready: make(chan struct{})} - memo.cache[key] = e - memo.mu.Unlock() + memo.mu.Lock() + e := memo.cache[key] + if e == nil { + // This is the first request for this key. + // This goroutine becomes responsible for computing + // the value and broadcasting the ready condition. + e = &entry{ready: make(chan struct{})} + memo.cache[key] = e + memo.mu.Unlock() - e.res.value, e.res.err = memo.f(key) + e.res.value, e.res.err = memo.f(key) - close(e.ready) // broadcast ready condition - } else { - // This is a repeat request for this key. - memo.mu.Unlock() + close(e.ready) // broadcast ready condition + } else { + // This is a repeat request for this key. + memo.mu.Unlock() - <-e.ready // wait for ready condition - } - return e.res.value, e.res.err + <-e.ready // wait for ready condition + } + return e.res.value, e.res.err } ``` @@ -263,13 +263,13 @@ type Func func(key string) (interface{}, error) // A result is the result of calling a Func. type result struct { - value interface{} - err error + value interface{} + err error } type entry struct { - res result - ready chan struct{} // closed when res is ready + res result + ready chan struct{} // closed when res is ready } ``` @@ -279,23 +279,23 @@ type entry struct { gopl.io/ch9/memo5 // A request is a message requesting that the Func be applied to key. type request struct { - key string - response chan<- result // the client wants a single result + key string + response chan<- result // the client wants a single result } type Memo struct{ requests chan request } // New returns a memoization of f. Clients must subsequently call Close. func New(f Func) *Memo { - memo := &Memo{requests: make(chan request)} - go memo.server(f) - return memo + memo := &Memo{requests: make(chan request)} + go memo.server(f) + return memo } func (memo *Memo) Get(key string) (interface{}, error) { - response := make(chan result) - memo.requests <- request{key, response} - res := <-response - return res.value, res.err + response := make(chan result) + memo.requests <- request{key, response} + res := <-response + return res.value, res.err } func (memo *Memo) Close() { close(memo.requests) } @@ -307,31 +307,31 @@ cache變量被限製在了monitor goroutine (\*Memo).server中,下面會看到 ```go func (memo *Memo) server(f Func) { - cache := make(map[string]*entry) - for req := range memo.requests { - e := cache[req.key] - if e == nil { - // This is the first request for this key. - e = &entry{ready: make(chan struct{})} - cache[req.key] = e - go e.call(f, req.key) // call f(key) - } - go e.deliver(req.response) - } + cache := make(map[string]*entry) + for req := range memo.requests { + e := cache[req.key] + if e == nil { + // This is the first request for this key. + e = &entry{ready: make(chan struct{})} + cache[req.key] = e + go e.call(f, req.key) // call f(key) + } + go e.deliver(req.response) + } } func (e *entry) call(f Func, key string) { - // Evaluate the function. - e.res.value, e.res.err = f(key) - // Broadcast the ready condition. - close(e.ready) + // Evaluate the function. + e.res.value, e.res.err = f(key) + // Broadcast the ready condition. + close(e.ready) } func (e *entry) deliver(response chan<- result) { - // Wait for the ready condition. - <-e.ready - // Send the result to the client. - response <- e.res + // Wait for the ready condition. + <-e.ready + // Send the result to the client. + response <- e.res } ``` @@ -343,5 +343,5 @@ func (e *entry) deliver(response chan<- result) { 上面的兩種方案併不好説特定情境下哪種更好,不過了解他們還是有價值的。有時候從一種方式切換到另一種可以使你的代碼更爲簡潔。(譯註:不是説好的golang推崇通信併發麽) -練習 9.3: 擴展Func類型和(\*Memo).Get方法,支持調用方提供一個可選的done channel,使其具備通過該channel來取消整個操作的能力(§8.9)。一個被取消了的Func的調用結果不應該被緩存。 +**練習 9.3:** 擴展Func類型和(\*Memo).Get方法,支持調用方提供一個可選的done channel,使其具備通過該channel來取消整個操作的能力(§8.9)。一個被取消了的Func的調用結果不應該被緩存。