這些天,Goroutines 和通道困擾著我。我正在查看https://github.com/adonovan/gopl.io/tree/master/ch9上的 memo5 代碼。如果你看 memo5 的 memo.go,有func (e *entry) call(f Func, key string)和func (e *entry) deliver(response chan<- result)部分。
// Copyright ? 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 278.
// Package memo provides a concurrency-safe non-blocking memoization
// of a function. Requests for different keys proceed in parallel.
// Concurrent requests for the same key block until the first completes.
// This implementation uses a monitor goroutine.
package memo
//! Func
// Func is the type of the function to memoize.
type Func func(key string) (interface{}, error)
// A result is the result of calling a Func.
type result struct {
value interface{}
err error
}
type entry struct {
res result
ready chan struct{} // closed when res is ready
}
//!-Func
//! get
// 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
}
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
}
func (memo *Memo) Get(key string) (interface{}, error) {
response := make(chan result)
memo.requests <- request{key, response}
res := <-response
return res.value, res.err
}
func (memo *Memo) Close() { close(memo.requests) }
//!-get
//! monitor
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)
}
}
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)
}
func (e *entry) deliver(response chan<- result) {
// Wait for the ready condition.
<-e.ready
// Send the result to the client.
response <- e.res
}
//!-monitor
我不明白如何在 close(e.ready)這里 <-e.ready同步。就算看完書,也看不懂。請告訴我機制是什么。
uj5u.com熱心網友回復:
e.ready更多地被稱為done 通道。這是一種通過關閉done( e.readychan) 來告訴您的 ref 函式 dothing 已準備好的方法。<-e.ready將阻塞直到它的done( closed)。
所以...閱讀此代碼意味著下一步。
deliver等待紅色信號。call獲取 e.res(e.res.value 的資料,e.res.err = f(key)`)call通過關閉它來釋放完成的通道 (close(e.ready))deliver可以通過塊讀取移動<-e.ready并將資料發送到response
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/424135.html
