Home > Mobile >  I don't understand the golang channel well
I don't understand the golang channel well

Time:02-15

Goroutines and channels are bothering me these days. I'm looking at the memo5 code at https://github.com/adonovan/gopl.io/tree/master/ch9. If you look at memo.go of memo5, there are func (e *entry) call(f Func, key string) and func (e *entry) deliver(response chan<- result) parts.

// 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

I don't understand how close(e.ready) and <-e.ready synchronize here. Even after reading the book, I don't understand. Please tell me what the mechanism is.

CodePudding user response:

e.ready is more known as done channel. this is a way to tell your ref functions that domething is ready by closing done (e.ready chan). <-e.ready is going to block until its done (closed).

so... reading this code it means next.

  1. deliver waits for rediness signal.
  2. call gets data for e.res (e.res.value, e.res.err = f(key)`)
  3. call releas done channel by closing it (close(e.ready))
  4. deliver can move throu block reading from <-e.ready and send data to response
  • Related