当前位置: 首页 > news >正文

注册个网站怎么注册东营会计信息网官网首页

注册个网站怎么注册,东营会计信息网官网首页,上海做网站谁好,虚拟主机评测注#xff1a;该项目原作者#xff1a;https://geektutu.com/post/geecache-day1.html。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。 支持并发读写 接下来我们使用 sync.Mutex 封装 LRU 的几个方法#xff0c;使之支持并发的读写。在这之…注该项目原作者https://geektutu.com/post/geecache-day1.html。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。 支持并发读写 接下来我们使用 sync.Mutex 封装 LRU 的几个方法使之支持并发的读写。在这之前我们抽象了一个只读数据结构 ByteView 用来表示缓存值是 GeeCache 主要的数据结构之一。 package project// A ByteView holds an immutable view of bytes. type ByteView struct {b []byte }// Len returns the views length func (v ByteView) Len() int {return len(v.b) }// ByteSlice returns a copy of the data as a byte slice. func (v ByteView) ByteSlice() []byte {return cloneBytes(v.b) }// String returns the data as a string, making a copy if necessary. func (v ByteView) String() string {return string(v.b) }func cloneBytes(b []byte) []byte {c : make([]byte, len(b))copy(c, b)return c }ByteView 只有一个数据成员b []byteb 将会存储真实的缓存值。选择 byte类型是为了能够支持任意的数据类型的存储例如字符串、图片等。 实现 Len() int 方法我们在 lru.Cache的实现中要求被缓存对象必须实现 Value 接口即 Len() int 方法返回其所占的内存大小。 b 是只读的使用 ByteSlice() 方法返回一个拷贝防止缓存值被外部程序修改。 接下来就可以为 lru.Cache 添加并发特性了。 package projectimport (goLang/project/lrusync )type cache struct {mu sync.Mutexlru *lru.CachecacheBytes int64 }func (c *cache) add(key string, value ByteView) {c.mu.Lock()defer c.mu.Unlock()if c.lru nil {c.lru 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 }···cache.go 的实现非常简单实例化 lru封装 get 和 add 方法并添加互斥锁 mu。在 add 方法中判断了 c.lru 是否为 nil如果等于 nil 再创建实例。这种方法称之为延迟初始化(Lazy Initialization)一个对象的延迟初始化意味着该对象的创建将会延迟至第一次使用该对象时。主要用于提高性能并减少程序内存要求。 主体结构Group Group 是 GeeCache 最核心的数据结构负责与用户的交互并且控制缓存值存储和获取的流程。 我们将在 geecache.go 中实现主体结构 Group那么 GeeCache 的代码结构的雏形已经形成了。 回调Getter 我们思考一下如果缓存不存在应从数据源文件数据库等获取数据并添加到缓存中。GeeCache 是否应该支持多种数据源的配置呢不应该一是数据源的种类太多没办法一一实现二是扩展性不好。如何从源头获取数据应该是用户决定的事情我们就把这件事交给用户好了。因此我们设计了一个回调函数(callback)在缓存不存在时调用这个函数得到源数据。 // A Getter loads data for a key. type Getter interface {Get(key string) ([]byte, error) }// A GetterFunc implements Getter with a function. type GetterFunc func(key string) ([]byte, error)// Get implements Getter interface function func (f GetterFunc) Get(key string) ([]byte, error) {return f(key) }定义接口 Getter 和 回调函数 Get(key string)([]byte, error)参数是 key返回值是[]byte。定义函数类型 GetterFunc并实现 Getter 接口的 Get 方法。函数类型实现某一个接口称之为接口型函数方便使用者在调用时既能够传入函数作为参数也能够传入实现了该接口的结构体作为参数。 我们可以写一个测试用例来保证回调函数能够正常工作。 func TestGetter(t *testing.T) {var f Getter GetterFunc(func(key string) ([]byte, error) {return []byte(key), nil})expect : []byte(key)if v, _ : f.Get(key); !reflect.DeepEqual(v, expect) {t.Errorf(callback failed)} }Group 的定义 接下来是最核心数据结构 Group 的定义 // A Group is a cache namespace and associated data loaded spread over type Group struct {name stringgetter GettermainCache cache }var (mu sync.RWMutexgroups make(map[string]*Group) )// NewGroup create a new instance of Group func NewGroup(name string, cacheBytes int64, getter Getter) *Group {if getter nil {panic(nil Getter)}mu.Lock()defer mu.Unlock()g : Group{name: name,getter: getter,mainCache: cache{cacheBytes: cacheBytes},}groups[name] greturn g }// GetGroup returns the named group previously created with NewGroup, or // nil if theres no such group. func GetGroup(name string) *Group {mu.RLock()g : groups[name]mu.RUnlock()return g }一个 Group 可以认为是一个缓存的命名空间每个 Group 拥有一个唯一的名称 name。比如可以创建三个 Group缓存学生的成绩命名为 scores缓存学生信息的命名为 info缓存学生课程的命名为 courses。第二个属性是 getter Getter即缓存未命中时获取源数据的回调(callback)。第三个属性是 mainCache cache即一开始实现的并发缓存。 构建函数 NewGroup 用来实例化 Group并且将group 存储在全局变量 groups 中。GetGroup 用来特定名称的 Group这里使用了只读锁 RLock()因为不涉及任何冲突变量的写操作。 Group 的 Get 方法 接下来是 GeeCache 最为核心的方法 Get // Get value for a key from cache func (g *Group) Get(key string) (ByteView, error) {if key {return ByteView{}, fmt.Errorf(key is required)}if v, ok : g.mainCache.get(key); ok {log.Println([GeeCache] hit)return v, nil} else {log.Println([cache] unhit)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.populateCache(key, value)return value, nil }func (g *Group) populateCache(key string, value ByteView) {g.mainCache.add(key, value) }Get 方法实现了上述所说的流程 ⑴ 和 ⑶。流程 ⑴ 从 mainCache 中查找缓存如果存在则返回缓存值。流程 ⑶ 缓存不存在则调用 load 方法load 调用 getLocally分布式场景下会调用 getFromPeer 从其他节点获取getLocally 调用用户回调函数 g.getter.Get() 获取源数据并且将源数据添加到缓存 mainCache 中通过 populateCache 方法 至此这一章节的单机并发缓存就已经完成了。 PS 为什么load方法定义为调用getlocally方法不能直接调用getlocally方法吗 分布式场景下load 会先从远程节点获取 getFromPeer失败了再回退到 getLocally设计时预留了。为后面的分布式场景下设计预留空间 测试 首先用一个 map 模拟耗时的数据库。 var db map[string]string{Tom: 630,Jack: 589,Sam: 567, }创建 group 实例并测试 Get 方法 func TestGet(t *testing.T) {loadCounts : make(map[string]int, len(db))gee : NewGroup(scores, 210, GetterFunc(func(key string) ([]byte, error) {log.Println([slow db] search key, key)if v, ok : db[key]; ok {if _, ok : loadCounts[key]; !ok {loadCounts[key] 0}loadCounts[key] 1return []byte(v), nil}return nil, fmt.Errorf(%s not exist, key)}))for k, v : range db {if view, err : gee.Get(k); err ! nil || view.String() ! v {t.Fatal(failed to get value of Tom)} // load from callback functionif _, err : gee.Get(k); err ! nil || loadCounts[k] 1 {t.Fatalf(cache %s miss, k)} // cache hit}if view, err : gee.Get(unknown); err nil {t.Fatalf(the value of unknow should be empty, but %s got, view)} }在这个测试用例中我们主要测试了 2 种情况1在缓存为空的情况下能够通过回调函数获取到源数据2在缓存已经存在的情况下是否直接从缓存中获取为了实现这一点使用 loadCounts 统计某个键调用回调函数的次数如果次数大于1则表示调用了多次回调函数没有缓存。 测试结果如下 上述测试的基本逻辑 第一次搜索db中的键–不存在打印[cache] unhit并调用load(key) -再调用getlocally(key)方法 -再调用Getter接口的Get方法也就是GetterFunc函数,打印[slow db] search key…-调用populateCache-调用add方法将键值对加入缓存池中 -第二次搜索db中的键 -存在打印[Cache] hit–结束一次循环
http://www.yayakq.cn/news/1091/

相关文章:

  • 什么网站可以做高三英语试题客户做网站要退款
  • 做网站怎么做推广石狮app网站开发
  • windows优化大师官网贵阳关键词优化平台
  • 校园网站建设情况wordpress 密码爆破
  • 两学一做网站条幅小说网站设计模板
  • 制作公司网站怎样收费中国建筑有几个工程局
  • 可以做代发货源的网站国内做交互网站
  • 山东网站建设哪家权威icp备案网站接入信息 ip地址段
  • 口碑好的网站建设商家用wordpress还是php
  • phpcms网站模板下载徐州网站建设 网站制作
  • 网站建设家乡网页设计模板网上注册公司需要什么材料和手续
  • 做网站能成功吗wordpress网站很慢
  • 浙江中联建设集团网站wordpress 没有中文
  • 建设中网站如何上传图片网页设计公司兴田德润在那里
  • 建商城网站需要什么条件制作网站得多少钱
  • 企业建站用什么软件杭州python做网站
  • 网站备案号找回密码国外ip地址怎么弄
  • 哪个网站容易做二级域名建网站用什么系统
  • 广州电子商务网站建设费用女同wordpress
  • 美团网站界面设计网站招聘怎么做
  • 免费的个人空间建网站网站开发网页权限如何控制
  • 中旅远洋商务网站建设策划书免费收录软文网站
  • wordpress 导航网站无二制造 网站升级建设中
  • wordpress注册模板下载seo关键词快速排名软件
  • 深圳做网站de公司优化网站做什么的
  • 建设教育网站法律网站的建设流程
  • app网站建设宣传方案怎么查网站建设时间
  • 八宝山做网站的公司家装公司十大口碑排名
  • 建设网站有哪些步骤网站空间查询
  • 合肥网站制作方案凡科互动答题辅助