golang——併發、重複抑制、非阻塞緩存

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"
	"time"
)

type entry struct {
	res   result
	ready chan struct{} // 重複抑制
}

type result struct {
	value interface{}
	err   error
}

type Memo struct {
	f     Func
	mu    sync.Mutex
	cache map[string]*entry // 本地緩存
}

type Func func(key string) (interface{}, error)

func New(f Func) *Memo {
	return &Memo{f: f, cache: make(map[string]*entry)}
}

func (memo *Memo) Get(key string) (interface{}, error) {
	memo.mu.Lock()
	e := memo.cache[key]
	if e == nil {
		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 {
		fmt.Println(key)
		memo.mu.Unlock()
		<-e.ready
	}
	return e.res.value, e.res.err
}

func httpGetBody(url string) (interface{}, error) {
	client := http.Client{Timeout: 1 * time.Second}
	resp, err := client.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

func incomingURLs() []string {
	return []string{
		"https://blog.csdn.net/liyuxing6639801",
		"https://zhuanlan.zhihu.com/p/95056679",
		"https://blog.csdn.net/chenbaoke/article/details/42782767",
		"https://www.jianshu.com/p/228c119a7d0e",
		"https://github.com/disintegration/imaging",
		"https://github.com/disintegration/imaging",
	}
}

func main() {
	m := New(httpGetBody)
	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 {
				fmt.Println(err)
				n.Done()
				return
			}
			fmt.Printf("%s, %s, %d bytes\n", url, time.Since(start), len(value.([]byte)))
			n.Done()
		}(url)
	}
	n.Wait()
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章