Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package main
- import (
- "io/ioutil"
- "log"
- "net/http"
- "sync"
- "time"
- )
- type entry struct {
- res result
- ready chan struct{}
- }
- type Func func(key string) (interface{}, error)
- type result struct {
- value interface{}
- err error
- }
- func New(f Func) *Memo {
- return &Memo{f: f, cache: make(map[string]*entry)}
- }
- type Memo struct {
- f Func
- mu sync.Mutex
- cache map[string]*entry
- }
- func (memo *Memo) Get(key string) (value interface{}, err error) {
- memo.mu.Lock()
- e := memo.cache[key]
- if e == nil {
- // Это первый запрос данного ключа
- // Эта go-подпрограмма становится ответственной за
- // вычисление значения и оповещение о готовности
- e = &entry{ready: make(chan struct{})}
- memo.cache[key] = e
- memo.mu.Unlock()
- e.res.value, e.res.err = memo.f(key)
- close(e.ready) // широковещательное оповещение о готовности
- } else {
- // это повторный запрос данного ключа
- memo.mu.Unlock()
- <-e.ready // ожидание готовности
- }
- return e.res.value, e.res.err
- }
- func main() {
- m := New(httpGetBody)
- var wg sync.WaitGroup
- for _, url := range []string{
- "http://example.com",
- "https://toster.ru",
- "https://habrahabr.ru",
- "http://example.com",
- "https://toster.ru",
- "https://habrahabr.ru",
- } {
- wg.Add(1)
- go func(url string) {
- defer wg.Done()
- start := time.Now()
- resp, err := m.Get(url)
- if err != nil {
- log.Println(err)
- }
- log.Printf("%s - %s (%d bytes)\n", url, time.Since(start), len(resp.([]byte)))
- }(url)
- }
- wg.Wait()
- }
- 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)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement