zoukankan      html  css  js  c++  java
  • 实验干货分享:用Go语言实现分布式缓存开发之map

    本实验是整个分布式缓存开发的基础实验,主要会使用 Go 语言的内置库完成一个单机版的缓存服务,后面会基于这个单机版的缓存服务来升级改造,逐步迭代成为一个分布式的缓存服务。本实验会使用 Go 语言的 map 来开发一个缓存结构,并使用 sync 包来保证并发安全,最后使用 http 包来提供网络服务。由于篇幅有限,这里仅展现map容器的使用,我会把后续和源代码放在文章最后,大家自取哦~

    知识点

    • Go map 容器的使用

    缓存的介绍

    缓存的第一印象
    我们先来看这样一个问题:一个程序有 1TB 的数据都存在硬盘上,但其中只有 1GB 的数据会被频繁地读取,假设硬盘的读取速度是 100MB/s,那么每一次读取都会消耗 10 秒,有没有什么办法可以提高读取的速度?

    很明显,这个问题是由于硬盘的速度太慢了,导致读取时间太久,而且只是其中 1GB 数据会被频繁地读取,那我们能不能把这 1GB 的数据存到一个速度更快的地方,比如存到内存中,假设内存速度是 10GB/s,那么每一次读取这 1GB 的数据就只需要 0.1 秒。可能有人会说,那为什么不把全部数据都存到内存中呢?当然可以,只要你有足够大的内存,但是内存的价格要比硬盘高不少,整个程序的花费就会非常大,而且其他数据存进内存的意义不大。

    如果要给这里的“内存”起一个名字,就可以叫它“缓存”了。我们不用去纠结缓存的概念是什么,更重要的是它解决了什么问题。

    缓存的特点
    还是从上面的问题入手,我们可以提取出两个关键点:频繁,速度。

    这两个关键点意味着缓存中的数据往往是会被反复读取的,因为经常要读取,所以要提高读取的速度。另外,由于数据本身是存在硬盘上的,所以不管缓存中有没有这些数据,程序都应该是正常运行的,当缓存中没有数据的时候,需要去硬盘中读取。如果程序修改了硬盘上的数据,缓存中的数据就没有用了,属于过时的数据,所以还需要去更新缓存。

    所以,我们可以总结出缓存的特点:

    • 速度很快(这个快是相对于被缓存的设备来说的)
    • 数据可以丢失(甚至需要定期丢失)
    • 容量有限(因为价格比较高)

    map 的常用操作

    map 的介绍
    Go 语言的 map 是一种键值对的结构,每一个键值对都分为 key 和 value 两个部分。在使用 map 的时候需要指定 key 和 value 的类型,其中 key 在 map 中是唯一的。下面让我们来学习几个 map 的常见操作:

    在后面的示例内容中,我们只会给到对应功能的代码,未给出完整程序,请自行补充 main 函数等内容。

    map 的创建

    func create() {
    
        // map 的创建需要指定 key 和 value 的类型
        // 其中 [] 中的类型是 key 的类型,[] 后面的类型是 value 的
    
        // 1. 使用 make 创建 map
        m1 := make(map[string]string)
        fmt.Println(m1) // map[]
    
        // 2. 直接创建 map
        m2 := map[string]string{}
        fmt.Println(m2) // map[]
    
        // 3. 创建 map 的同时添加数据
        m3 := map[string]string{
            "key": "value",
        }
        fmt.Println(m3) // map[key:value]
    }
    

    运行截图:
    请添加图片描述

    map 的增删改查

    func crud() {
    
        // 创建 map
        m := make(map[string]string)
        fmt.Println(m) // map[]
    
        // 添加数据
        m["key"] = "value"
        fmt.Println(m) // map[key:value]
    
        // 修改数据
        m["key"] = "newValue"
        fmt.Println(m) // map[key:newValue]
    
        // 查询数据
        // 第一个返回值是数据,第二个返回值表示 key 是否存在
        value, ok := m["key"]
        fmt.Println(value, ok) // newValue true
        value, ok = m["not existed key"]
        fmt.Println(value, ok) //  false,这里的 value 是空字符串
    
        // 删除数据
        delete(m, "key")
    }
    

    运行截图:

    请添加图片描述

    map 的其他操作

    func other() {
    
        // 创建 map
        m := map[string]int{
            "a": 1,
            "b": 3,
            "c": 4,
            "d": 2,
            "e": 0,
        }
    
        // 遍历 map 可以使用 for range
        // 每一次遍历 map 的顺序可能都是不一样的
        for key, value := range m {
            fmt.Println(key, value) // 乱序打印出 m 中的 key 和 value
        }
    
        // 查看 map 中的键值对个数
        count := len(m)
        fmt.Println(count) // 5
    }
    

    运行截图:

    请添加图片描述

    第一个热身实验的第一部分就到这里啦。后续我们经过开发可以完成单机版缓存,之后会进行迭代,升级成分布式缓存。

    怎么样,是不是 so easy 啊,别急,后面我们会遇到各种各样的难题,需要大家一起拿起“屠龙刀”去杀敌。

    本章节代码可以直接获取:

    wget 
    https://labfile.oss.aliyuncs.com/courses/2943/code1.zip
    

    参考资料

  • 相关阅读:
    Android Studio快速定位当前文件所在的位置
    LeetCode:Search Insert Position
    apk当安装程序将文件复制到手机自带的指定文件夹
    《UNIX级别编程环境》注意读出信号(2)
    iOS:删除小程序
    百度CSND博客在搜索栏中显示图片
    HDU4893:Wow! Such Sequence!(段树lazy)
    Google I/O 2014? No,Android I/O 2014
    Android Push Notifications using Google Cloud Messaging (GCM), PHP and MySQL
    自己动手写CPU 笔记
  • 原文地址:https://www.cnblogs.com/shiyanlou/p/15134131.html
Copyright © 2011-2022 走看看