天道酬勤

天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。

0%

 在平时学习过很多Redis的知识点,解决过很多问题,但是感觉整体比较零散。为了比较系统、完整的了解Redis,总结出一篇博客,方便自己和大家了解。

 在看内容之前,先问大家一个问题,在使用redis get命令和set命令时,大家知道Redis是怎么执行的,涉及到哪些模块吗?

(1) Redis架构

 Redis架构

Redis系统架构主要包含 事件处理、数据管理、功能扩展、系统扩展等内容。

阅读全文 »

  相比于 Go 语言宣扬的“用通讯的方式共享数据”,通过共享数据的方式来传递信息和协调线程运行的做法其实更加主流,毕竟大多数的现代编程语言,都是用后一种方式作为并发编程的解决方案的。
  我们来了解一下go中的互斥锁sync.Mutex

(1) sync.Mutex是什么

  sync.Mutex是go语言里的一种互斥锁,是保证同步的一种工具。
  类似生活中去医院看病时挂号等医生叫号的过程,有很多患者挂号(协程),只有一个医生(资源),被叫号的患者(拿到锁)可以到诊室里让医生看病。看完病离开诊室(释放锁)。


(2) 为什么要用sync.Mutex

先看一个例子

package main

import "sync"

var sum int = 0
var wg sync.WaitGroup
var mu sync.Mutex

// 开10个协程并发执行1000次 sum++
// 如果不加 mu.lock() mu.unlock() 最后的结果不是10000 一般会小于10000
// 把 // mu.lock() // mu.unlock() 前面的注释删除,结果就是10000
// 这个是缓存导致的可见性问题。
// 具体原因是因为sum++不是原子操作,CPU分2条指令执行,CPU执行第2条指令时获取到的缓存sum值和主内存sum值不一致导致
func main() {

	// fatal error: sync: unlock of unlocked mutex
	// // mu.Unlock()

	// 开10个协程并发执行1000次 sum=sum+1
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go funcAdd()
	}
	// 等所有协程执行完
	wg.Wait()
	println("result:", sum)

}

func funcAdd() {
	for i := 0; i < 1000; i++ {
		// 对sum加锁
		//mu.Lock()
		sum++
		// 对sum解锁
		//mu.Unlock()
		//println("result=", sum)
	}
	// 没有下面这一行代码 提示 fatal error: all goroutines are asleep - deadlock!
	wg.Done()
}

上面的代码主要功能是开10个协程并发执行1000次 sum++,并打印结果,可以自己执行一下,会发现执行的结果<10000。
把第33行 36行前的注释删掉,程序执行的结果就是结果就是10000

阅读全文 »

接口泛指实体把自己提供给外界的一种抽象化物(可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被内部修改而不影响外界其他实体与其交互的方式。

比如有了type-c接口,大家都可以用type-c去充电。不用每种手机一种充电器。
电脑有了usb接口,只要是usb接口的硬件,都可以使用。

 

(1) Go语言接口类型的作用

接口类型的基础知识,包括接口类型的声明、接口类型变量的定义与初始化以及类型断言

接口类型与 Go 并发语法恰分别是耦合设计与并发设计的主要参与者,因此 Go 应用的骨架设计离不开它们。一个良好的骨架设计又决定了应用的健壮性、灵活性与扩展性,甚至是应用的运行效率。

(1.1) 接口

接口类型是由 type 和 interface 关键字定义的一组方法集合,其中,方法集合唯一确定了这个接口类型所表示的接口。

// Animal 动物接口
type Animal interface {
	Say() string
	Eat() string
}
阅读全文 »

多态是同一个行为具有多个不同表现形式或形态的能力。
比如动物都会叫,但是不同种类的动物叫的声音不一样。

Go 语言并没有设计诸如虚函数、纯虚函数、继承、多重继承等概念,但它通过接口却非常优雅地支持了面向对象的特性。

多态是一种运行期的行为,它有以下几个特点:
1、一种类型具有多种类型的能力
2、允许不同的对象对同一消息做出灵活的反应
3、以一种通用的方式对待个使用的对象
4、非动态语言必须通过继承和接口的方式来实现

通过接口实现多态

type Animal interface {
	Say() string
}
// dog
type Dog struct {
}

func (d Dog) Say() string {
	// 汪汪
	return "汪"
}
// cat
type Cat struct {
}

func (c Cat) Say() string {
	// 喵喵
	return "喵"
}
package main

import "fmt"

func main() {
	animals := []Animal{Dog{}, Cat{}}
	for _, animal := range animals {
		fmt.Println(animal.Say())
	}
}
阅读全文 »

泛型编程的中心思想是对具体的、高效的算法进行抽象,以获得通用的算法,然后这些算法可以与不同的数据表示法结合起来,产生各种各样有用的软件。
简单了说是将算法与类型解耦,实现算法更广泛的复用。

 泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。

func AddInt8(a int8, b int8) int8 {
	return a + b
}

func AddInt16(a int16, b int16) int16 {
	return a + b
}

func AddInt32(a int32, b int32) int32 {
	return a + b
}

func AddInt64(a int64, b int64) int64 {
	return a + b
}

大家看到上面的代码有没有问题,感觉逻辑都是a+b,但是写了多次,如果有几十种类型,是不是要写对应几十个方法?

(1) 泛型

 
 泛型是一种编程范式,这种范式与特定的类型无关,泛型允许在函数和类型的实现中使用某个类型集合中的任何一种类型。

阅读全文 »

通用的、对实体对象进行聚合抽象的能力。
在 Go 中,提供这种聚合抽象能力的类型是结构体类型,也就是 struct。

阅读全文 »

 设计哲学之于编程语言,就好比一个人的价值观之于这个人的行为。 如果你不知道为什么这么设计,会遇到很多很“别扭”的问题。

Go语言的设计哲学总结为五点:简单、显式、组合、并发和面向工程。

阅读全文 »

map是Go语言提供的一种抽象数据类型,它表示一组无序的键值对。
 map对应数据结构里的哈希表

(1) map类型介绍

map 类型对 value 的类型没有限制,但是对 key 的类型却有严格要求,因为 map 类型要保证 key 的唯一性。Go 语言中要求,key 的类型必须支持“==”和“!=”两种比较操作符。

注意:函数类型、map 类型自身,以及切片类型是不能作为 map 的 key 类型的。

map的基本操作

定义map

// 声明map
var map1 map[string]string
// 初始化map
map1 = make(map[string]string, 16)
阅读全文 »

负载均衡笔记

(1) 负载均衡算法

常见的几种负载均衡算法: 轮询法、随机法、源地址哈希法、加权轮询法、加权随机法、最小连接数法

阅读全文 »