极客兔兔Gee-Cache Day2

  • 接口型函数

    • // 定义接口
      type Getter interface {
      	Get(key string) ([]byte, error)
      }
      
      // 定义函数
      type GetterFunc func(key string) ([]byte, error)
      
      // 实现接口
      func (f GetterFunc) Get(key string) ([]byte, error) {
      	return f(key)
      }
      
    • 价值:能将普通的函数类型作为参数,也能将结构体作为参数,使用更为灵活

    • 例如:

      • // 若GetFromSource定义如下,需要传一个Getter作为参数
        func GetFromSource(getter Getter, key string) []byte
        // 1.传函数(匿名函数和非匿名函数,下面是匿名)
        // 将函数类型转换为GetterFunc,这是实现了Getter接口的,可以传
        GetFromSource(GetterFunc(func(key string) ([]byte, error) {
        	return []byte(key), nil
        }), "hello")
        // 2.传结构体
        type DB struct{ url string}
        func (db *DB) Get(key string) ([]byte, error) {
        	// ...
        	return []byte(v), nil
        }
        func main() {
        	GetFromSource(new(DB), "hello")
        }
        
    • net/http包下的Handler就是使用这种特性

      • type Handler interface {
        	ServeHTTP(ResponseWriter, *Request)
        }
        type HandlerFunc func(ResponseWriter, *Request)
        
        func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
        	f(w, r)
        }
        
  • sync.Mutex:Go 语言标准库提供的一个互斥锁,当一个协程(goroutine)获得了这个锁的拥有权后,其它请求锁的协程(goroutine) 就会阻塞在 Lock() 方法的调用上,直到调用 Unlock() 锁被释放。

  • reflect.DeepEqual()

    • 对于基本数据类型(整数、布尔、字符串),与==相同
    • 可以比较数组、切片、结构体、map、接口等是否相同
    • 对于切片,必须切片长度相等且顺序相同,元素相同
  • day2由四个文件组成,分别是lru.gobyteview.gocache.gogeecache.go

    • lru.golru缓存淘汰策略

    • byteview.go:缓存值,实现了Value接口

    • cache.go:并发控制

    • geecache.go:与外部交互,在缓存未命中时去查找数据源

    • cache.goday1中的lru加入了锁机制,实现并发下的互斥访问,geecache.go中实现了Group结构体,其中包含cache和回调函数,在cache未命中时会调用回调函数查找数据库中的内容,同时,使用map结构分配多个缓存,用name进行区分,每个Group有一个唯一的name(例如学生成绩和学生课程的缓存使用不同的name区分)

    • 代码

      // ---------------------------------------------------------------------------------------
      // ByteView.go 缓存元素的抽象
      package gee
      
      // 只读数据结构 表示缓存值,实现了Value接口
      type ByteView struct {
      	b []byte
      }
      
      func (v ByteView) Len() int {
      	return len(v.b)
      }
      
      func (v ByteView) ByteSlice() []byte {
      	return cloneBytes(v.b)
      }
      
      func cloneBytes(b []byte) []byte {
      	c := make([]byte, len(b))
      	copy(c, b)
      	return c
      }
      
      func (v ByteView) String() string {
      	return string(v.b)
      }
      // cache.go 对day1中的lru加上并发控制
      package gee
      // ---------------------------------------------------------------------------------------
      // 实现并发控制
      import (
      	"sync"
      )
      
      type cache struct {
      	mu         sync.Mutex
      	lru        *Cache
      	cacheBytes int64
      }
      
      func (c *cache) add(key string, value ByteView) {
      	c.mu.Lock()
      	defer c.mu.Unlock()
      	if c.lru == nil { // 延迟初始化
      		c.lru = New(c.cacheBytes, nil)
      	}
      	c.lru.Add(key, value)
      }
      
      func (c *cache) get(key string) (value ByteView, ok bool) {
      	c.mu.Lock()
      	defer c.mu.Unlock()
      	if c.lru == nil {
      		return
      	}
      	if v, ok := c.lru.Get(key); ok {
      		return v.(ByteView), ok
      	}
      	return
      }
      // ---------------------------------------------------------------------------------------
      // geecache.go 与源数据库进行交互
      package gee
      
      // 实现与外部交互
      import (
      	"fmt"
      	"sync"
      )
      
      type Getter interface {
      	Get(key string) ([]byte, error)
      }
      
      type GetterFunc func(key string) ([]byte, error)
      
      // 接口型函数
      func (f GetterFunc) Get(key string) ([]byte, error) {
      	return f(key)
      }
      
      type Group struct {
      	name      string // 缓存名称
      	getter    Getter // 回调函数
      	mainCache cache  // 缓存
      }
      
      var (
      	mu     sync.Mutex
      	groups = make(map[string]*Group)
      )
      
      func NewGroup(name string, cacheBytes int64, getter Getter) *Group {
      	if getter == nil {
      		panic("Getter nil")
      	}
      	mu.Lock()
      	defer mu.Unlock()
      	g := &Group{
      		name:      name,
      		getter:    getter,
      		mainCache: cache{cacheBytes: cacheBytes},
      	}
      	groups[name] = g
      	return g
      }
      
      func GetGroup(name string) *Group {
      	mu.Lock()
      	defer mu.Unlock()
      	g := groups[name]
      	return g
      }
      
      func (g *Group) Get(key string) (ByteView, error) {
      	if key == "" {
      		return ByteView{}, fmt.Errorf("key is nil")
      	}
      	if v, ok := g.mainCache.get(key); ok {
      		fmt.Println("Gee Cache hit")
      		return v, nil
      	}
      	return g.load(key)
      }
      
      func (g *Group) load(key string) (Value ByteView, err error) {
      	return g.getLocally(key)
      }
      
      // 调用回调函数,去源数据库查找内容
      func (g *Group) getLocally(key string) (ByteView, error) { 
      	bytes, err := g.getter.Get(key)
      	if err != nil {
      		return ByteView{}, err
      	}
      	value := ByteView{b: cloneBytes(bytes)}
      	g.add(key, value)
      	return value, nil
      
      }
      
      func (g *Group) add(key string, value ByteView) {
      	g.mainCache.add(key, value)
      }
      
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值