Advertisement
Guest User

Untitled

a guest
Sep 21st, 2017
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 1.90 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "io/ioutil"
  5.     "log"
  6.     "net/http"
  7.     "sync"
  8.     "time"
  9. )
  10.  
  11. type entry struct {
  12.     res   result
  13.     ready chan struct{}
  14. }
  15.  
  16. type Func func(key string) (interface{}, error)
  17. type result struct {
  18.     value interface{}
  19.     err   error
  20. }
  21.  
  22. func New(f Func) *Memo {
  23.     return &Memo{f: f, cache: make(map[string]*entry)}
  24. }
  25.  
  26. type Memo struct {
  27.     f     Func
  28.     mu    sync.Mutex
  29.     cache map[string]*entry
  30. }
  31.  
  32. func (memo *Memo) Get(key string) (value interface{}, err error) {
  33.     memo.mu.Lock()
  34.     e := memo.cache[key]
  35.     if e == nil {
  36.         // Это первый запрос данного ключа
  37.         // Эта go-подпрограмма становится ответственной за
  38.         // вычисление значения и оповещение о готовности
  39.         e = &entry{ready: make(chan struct{})}
  40.         memo.cache[key] = e
  41.         memo.mu.Unlock()
  42.  
  43.         e.res.value, e.res.err = memo.f(key)
  44.  
  45.         close(e.ready) // широковещательное оповещение о готовности
  46.     } else {
  47.         // это повторный запрос данного ключа
  48.         memo.mu.Unlock()
  49.         <-e.ready // ожидание готовности
  50.     }
  51.     return e.res.value, e.res.err
  52. }
  53.  
  54. func main() {
  55.     m := New(httpGetBody)
  56.     var wg sync.WaitGroup
  57.     for _, url := range []string{
  58.         "http://example.com",
  59.         "https://toster.ru",
  60.         "https://habrahabr.ru",
  61.         "http://example.com",
  62.         "https://toster.ru",
  63.         "https://habrahabr.ru",
  64.     } {
  65.         wg.Add(1)
  66.         go func(url string) {
  67.             defer wg.Done()
  68.             start := time.Now()
  69.             resp, err := m.Get(url)
  70.             if err != nil {
  71.                 log.Println(err)
  72.             }
  73.             log.Printf("%s - %s (%d bytes)\n", url, time.Since(start), len(resp.([]byte)))
  74.         }(url)
  75.  
  76.     }
  77.     wg.Wait()
  78.  
  79. }
  80.  
  81. func httpGetBody(url string) (interface{}, error) {
  82.     resp, err := http.Get(url)
  83.     if err != nil {
  84.         return nil, err
  85.     }
  86.     defer resp.Body.Close()
  87.     return ioutil.ReadAll(resp.Body)
  88. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement