鸭子类型介绍

鸭子类型 定义 鸭子类型(英语:duck typing)在程序设计中是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合“决定。这个概念的名字来源于由詹姆斯·惠特科姆·莱利提出的鸭子测试(见下面的“历史”章节),“鸭子测试”可以这样表述: ​ “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。” 在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为"鸭子"的对象,并调用它的"走"和"叫"方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的"走"和"叫"方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的"走"和"叫"方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。 鸭子类型通常得益于"不"测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。 在常规类型中,我们能否在一个特定场景中使用某个对象取决于这个对象的类型,而在鸭子类型中,则取决于这个对象是否具有某种属性或者方法——即只要具备特定的属性或方法,能通过鸭子测试,就可以使用。 多态 为什么会在鸭子类型中去介绍多态这个东西,众所周知,面向对象编程的三大特点 继承、封装、多态 ...

6 min · 2634 words · Luenci

RESTful风格

RESTful设计方法 原文参考自哔哩哔哩: https://www.bilibili.com/video/BV1k5411p7Kp 1. 域名 应该尽量将API部署在专用域名之下。 1 https://api.example.com 如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。 1 https://example.org/api/ 2. 版本(Versioning) 应该将API的版本号放入URL。 ...

5 min · 2182 words · Luenci

同源和跨域

原文:同源策略、跨域解决方案 一、同源策略 1、先来说说什么是源 • 源(origin)就是协议、域名和端口号。 以上url中的源就是:http://www.company.com:80 若地址里面的协议、域名和端口号均相同则属于同源。 以下是相对于 http://www.a.com/test/index.html 的同源检测 ...

3 min · 1051 words · Luenci

Django信号量初探

django的信号量 原文链接:https://juejin.cn/post/6844903674049724424 一、关于django信号量 Django包含一个"信号调度程序",它有助于在框架中的其他位置发生操作时通知分离的应用程序。简而言之,信号允许某些发送者通知一组接收器已经发生了某些动作。当许多代码可能对同一事件感兴趣时,它们特别有用. 二、django中内置的信号量 1、Model的信号量 pre_init # django的modal执行其构造方法前,自动触发 post_init # django的modal执行其构造方法后,自动触发 pre_save # django的modal对象保存前,自动触发 post_save # django的modal对象保存后,自动触发 pre_delete # django的modal对象删除前,自动触发 post_delete # django的modal对象删除后,自动触发 m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发 class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发 1 2 3 4 5 6 7 8 from django.db.models.signals import class_prepared from django.db.models.signals import pre_init from django.db.models.signals import post_init from django.db.models.signals import pre_save from django.db.models.signals import post_save from django.db.models.signals import pre_delete from django.db.models.signals import post_delete from django.db.models.signals import m2m_changed 2、Management的信号量 pre_migrate # 执行migrate命令前,自动触发 post_migrate # 执行migrate命令后,自动触发 1 2 from django.db.models.signals import pre_migrate from django.db.models.signals import post_migrate 3、Request/Response的信号量 request_started # 请求到来前,自动触发 request_finished # 请求结束后,自动触发 got_request_exception # 请求异常后,自动触发 1 2 3 from django.core.signals import request_finished from django.core.signals import request_started from django.core.signals import got_request_exception 4、Test的信号量 setting_changed # 使用test测试修改配置文件时,自动触发 template_rendered # 使用test测试渲染模板时,自动触发 1 2 from django.test.signals import setting_changed from django.test.signals import template_rendered 5、Database的信号量 connection_created # 创建数据库连接时,自动触发 1 from django.db.backends.signals import connection_created ...

4 min · 1767 words · Luenci

行为型模式

行为型模式 行为型模式,顾名思义,它主要关注的是对象的责任。 它们关注对象之间的交互以及对象的响应性 对象应该能够交互,同时仍然保持松散耦合 观察者模式 在观察者设计模式中,对象(主题)维护了一个依赖(观察者)列表,以便主题可以使用观察者定义的任何方法通知所有观察者它所发生的变化。 它定义了对象之间的一对多的依赖关系,从而使得一个对象中的任何更改都将自动通知给其他对象 它封装了主题的核心组件 UML图 主题(Subject):类Subject需要了解Observe。Subject类具有许多方法,诸如register()和deregister()等,Observer可以通过这些方法注册到Subject类中。因此,一个Subject可以处理多个Observe。 观察者(Observe):它为关注主题的对象定义了一个接口。它定义了Observe需要实现的各个方法,以便在主题发生变化时能够获得相应的通知。 具体观察者(ConcreteObserver):它用来保存应该与Subject的状态保持一致的状态。它实现了Observe接口以保持其状态与主题中的变化相一致。 代码案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #!/usr/bin/env python # -*- coding: utf-8 -*- class Subject(object): def __init__(self): self.__observer = [] def register(self, observer): self.__observer.append(observer) def notifyAll(self, *args, **kwargs): for observer in self.__observer: observer.notify(self, *args, **kwargs) class Observer1(object): def __init__(self, subject): subject.register(self) def notify(self, subject, *args): print(f"{type(self).__name__}:: Got, {args} from {subject}") class Observer2(object): def __init__(self, subject): subject.register(self) def notify(self, subject, *args): print(f"{type(self).__name__}:: Got, {args} from {subject}") if __name__ == '__main__': subject = Subject() observer1 = Observer1(subject) observer2 = Observer2(subject) subject.notifyAll("notify~~~") 观察者模式的优点和缺点 优点: 它使得彼此交互的对象之间保持送耦合 它使得我们可以在无需对主题或观察者进行任何修改的情况下高效地发送数据到其他对象 可以随时添加/删除观察者 缺点: 观察者接口必须由具体观察者实现,这涉及继承。无法进行组合,因为观察者接口可以实例化 如果实现不当的话,观察者可能会增加复杂性,并导致性能降低 在软件应用程序中,通知有时可能是不可靠的,并导致竞争条件或不一致性 ...

11 min · 5423 words · Luenci

结构型模式

结构型模式 结构型模式用于设计对象和类的结构,从而使它们之间可以互相协作以获取更大的结构。 结构型模式描述如何将对象和类组合成更大的结构 结构型模式是一种能够简化设计工作的模式,因为它能够找出更简单的方法来认识或表示实体之间的关系。在面向对象世界中,实体指的是对象或类 类模式可以通过继承来描述对象,从而提供更有用的程序接口,而对象模式则描述了如何将对象联系起来从而组合成更大的对象。结构型模式是类和对象模式的综合体 门面设计模式 它为子系统的一组接口提供一个统一的接口,并定义一个高级接口来帮助客户端通过更加简单的方式使用子系统 门面模式解决的问题是,如何用的单个接口对象来表示复杂的子系统。实际上它并不是封装子系统,而是对底层子系统进行组合 它促进了实现与多个客户端的解耦 UML图 代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 #!/usr/bin/env python # -*- coding: utf-8 -*- class EventManager(object): def __init__(self): print("Event Manager:: Let me talk to the folks\\n") def arrange(self): self.hotelier = Hotelier() self.hotelier.bookHotel() self.florist = Florist() self.florist.setFlowerRequirements() self.caterer = Caterer() self.caterer.setCuisine() self.musiccian = Musician() self.musiccian.setMusicType() class Hotelier(object): def __init__(self): print("Arranging the hotel for Marriage ?") def __isAvailable(self): print("Is the Hotel free for the event on given day?") return True def bookHotel(self): if self.__isAvailable(): print("Register the Booking \\n\\n") class Florist(object): def __init__(self): print("Flower Decorations for the Event ? --") def setFlowerRequirements(self): print("Carnations, Rose and Lilies would be used for Decorations\\n\\n") class Caterer(object): def __init__(self): print("Food Arrangements for the Event --") def setCuisine(self): print("Chinese & Continental Cuisine to be served \\n\\n") class Musician(object): def __init__(self): print("Musical Arrangements for the Marriage --") def setMusicType(self): print() class You(object): def __init__(self): print("you::whoa Marriage Arrangements !") def askEventManager(self): print("you:: Let is Contact the Event Manager\\n\\n") em = EventManager() em.arrange() def __del__(self): print("All preparations done!") if __name__ == '__main__': you = You() you.askEventManager() out: you::whoa Marriage Arrangements ! you:: Let is Contact the Event Manager Event Manager:: Let me talk to the folks Arranging the hotel for Marriage ? Is the Hotel free for the event on given day? Register the Booking Flower Decorations for the Event ? -- Carnations, Rose and Lilies would be used for Decorations Food Arrangements for the Event -- Chinese & Continental Cuisine to be served Musical Arrangements for the Marriage -- All preparations done! 小结 EventManager类是简化接口的门面 EventManager 通过组合创建子系统对象,如Hotelier,Florist等。 ...

7 min · 3087 words · Luenci

创建型模式

预备知识 @abstractmethod:抽象方法,含abstractmethod方法的类不能实例化,继承了含abstractmethod方法的子类必须复写所有abstractmethod装饰的方法,未被装饰的可以不重写 @ property:方法伪装属性,方法返回值及属性值,被装饰方法不能有参数,必须实例化后调用,类不能调用 @ classmethod:类方法,可以通过实例对象和类对象调用,被该函数修饰的方法第一个参数代表类本身常用cls,被修饰函数内可调用类属性,不能调用实例属性 @staticmethod:静态方法,可以通过实例对象和类对象调用,被装饰函数可无参数,被装饰函数内部通过类名.属性引用类属性或类方法,不能引用实例属性 创建型模式 创建型模式的工作原理是基于对象的创建机制的。由于这些模式隔离了对象的创建细节。所以使得代码能够与要创建的对象的类型互相独立。 它们的运行机制基于对象的创建方式 它们将对象创建的细节隔离开来 代码与所创建的对象的类型无关 单例模式 单例模式提供了这样一种机制,即确保类有且只有一个特定类型的对象,并提供全局访问点 UML图 代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 In [1]: class Singleton(object): """ 单例模式 """ ...: def __new__(cls): ...: if not hasattr(cls, "instance"): ...: cls.instance = super(Singleton, cls).__new__(cls) ...: return cls.instance ...: In [2]: s = Singleton() In [3]: s Out[3]: <__main__.Singleton at 0x7fc32793ed90> In [4]: s2 = Singleton() In [5]: s2 Out[5]: <__main__.Singleton at 0x7fc32793ed90> In [21]: class Singletons(object): """ 懒汉式加载 """ ...: __instance = None ...: def __init__(self): ...: if not Singletons.__instance: ...: print("__init__ method called..") ...: else: ...: print("Instance alreadly created:",self.getInstance()) ...: @classmethod ...: def getInstance(cls): ...: if not cls.__instance: ...: cls.__instance = Singletons() ...: return cls.__instance ...: In [22]: a = Singletons() __init__ method called.. In [23]: a1 = Singletons() __init__ method called.. In [24]: a2 = Singletons() __init__ method called.. In [25]: a.getInstance() __init__ method called.. Out[25]: <__main__.Singletons at 0x7fc327b020d0> In [26]: a Out[26]: <__main__.Singletons at 0x7fc327e48ca0> In [27]: a1 Out[27]: <__main__.Singletons at 0x7fc32763a250> In [1]: class MyMetaClass(type): """ 元类实现单例模式 """ ...: _instances = {} ...: def __call__(cls,*args,**kwargs): ...: print("**** Here`s my MetaClass ****") ...: if cls not in cls._instances: ...: cls._instances[cls] = super(MyMetaClass,cls).__call__(*args,**kwargs) ...: return cls._instances[cls] In [2]: class test(metaclass=MyMetaClass): ...: pass ...: In [3]: a = test() **** Here`s my MetaClass **** In [4]: a2 = test() **** Here`s my MetaClass **** In [5]: id(a) Out[5]: 139837183079520 In [6]: id(a2) Out[6]: 139837183079520 虽然单例模式在许多情况下效果很好,但是由于单例模式具有全局访问权限,可能会存在一些问题 全局变量可能在某处已经被更改,但是开发人员仍然认为它们没有发生变化,而改变量还在应用程序的其他位置被使用 可能会对同一个对象创建多个应用(此单例类被多次实例化,实际只实例化一次就可以) 所有依赖于全局变量的类都会由于一个类的改变而紧密耦合为全局数据,从而可能在无意中影响另一个类 ...

5 min · 2056 words · Luenci

设计模式

设计模式 设计模式设计模式是针对软件开发中经常遇到的一些设计问题,总结出来的一套解决方案或者设计思路。大部分设计模式要解决的都是代码的可扩展性问题。设计模式相对于设计原则来说,没有那么抽象,而且大部分都不难理解,代码实现也并不复杂。这一块的学习难点是了解它们都能解决哪些问题,掌握典型的应用场景,并且懂得不过度应用。 ...

4 min · 1748 words · Luenci

Python元类学习

你想通过改变实例创建方式来实现单例、缓存或其他类似的特性。 类的创建过程 https://docs.python.org/3/reference/datamodel.html#metaclasses 当 Python 见到 class 关键字时,会首先解析 class ... 中的内容。例如解析基类信息,最重要的是找到对应的元类信息(默认是 type)。 元类找到后,Python 需要准备 namespace (也可以认为是上节中 type 的 dict 参数)。如果元类实现了 __prepare__ 函数,则会调用它来得到默认的 namespace 。 之后是调用 exec 来执行类的 body,包括属性和方法的定义,最后这些定义会被保存进 namespace。 上述步骤结束后,就得到了创建类需要的所有信息,这时 Python 会调用元类的构造函数来真正创建类。 如果你想在类的创建过程中做一些定制(customization)的话,创建过程中任何用到了元类的地方,我们都能通过覆盖元类的默认方法来实现定制。这也是元类“无所不能”的所在,它深深地嵌入了类的创建过程。 type动态创建类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 常规方法创建类 class Foo(object): name = "luenci" def func(self): return 666 # 基于type创建类 # - 类名 # - 继承的类 # - 类属性 # - 类方法 foo1 = type("Foo", (object,), {"name": "luenci", "func": lambda self: "hi"}) ...

2 min · 729 words · Luenci

Go语言基础知识和语法

Go语言特点 没有头文件概念,.go后缀 强类型语言,编译型语言 一个go语言的应用程序,在运行的时候是不需要依赖外部库的 把执行时需要的库都打包到程序中 go程序比较大 如果import的包没有使用,那么程序不允许编译 go语法不区分平台的,在windos下面编译的一个程序,可以在Linux上运行,需要配置环境变量来控制 GOOS:设定运行平台 mac:darwin linux:linux windos:windos GOARCH:目标平台的体系架构 386 amd64 arm Go命令 go build -o 生成文件名.exe 编译文件名.go go run *.go 直接运行程序不会编译成exe文件 安装程序 ./configure make make install —>将编译好的程序安装到指定目录 go install 将编译后的可执行文件安装到 GOBIN 目录下 go mod 参数 go mod 资料连接 go mod 使用 开始使用 Go Module 依赖包存储位置 使用go get获取的包放在$GOPATH/src/目录下 使用go mod下载的依赖包放在$GOPATH/pkg/mod/目录下,所有项目共享 Go目录结构 一般的,一个Go项目在GOPATH下,会有如下三个目录: 一般,bin和pkg目录可以不创建,go命令会自动创建(如 go install),只需要创建src目录即可。 1 2 3 |--bin |--pkg |--src bin存放编译后的可执行文件 1 pkg 存放编译后的包文件 pkg中的文件是Go编译生成的,而不是手动放进去的 src存放项目源文件 Go数据类型 go语言不支持隐式类型转换 比如从int 转为 int 64就会发生编译错误 显示类型转换和隐式类型转换 当两种或多种数据类型进行某种操作时,不需要干预,系统会自动进行隐式转换。 但你需要把一个 long 类型的数据转成 int 时,又或者让 string 与 int 互转,当数据小数点太多时,这时候就必须使用 显式转型 Golang的零值 Go语言中的零值是变量没有做初始化时系统默认设置的值。 所有其他数值型的类型(包括complex64/128)零值都是0,可以用常量表达式代表数值0的任何形式表示出来。 但是类型不能混用,变量类型和零值类型必须匹配。 布尔类型的零值(初始值)为 false,数值类型的零值为 0,字符串类型的零值为空字符串"",而指针、切片、映射、通道、函数和接口的零值则是 nil。 ...

11 min · 5194 words · Luenci

Go面向对象相关知识

Go面向对象相关知识 类的封装和绑定方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package main import "fmt" // go语言没有class关键字生成类 // 使用struct声明类 type Person struct { // 成员属性 name string age int gender string } // 类外边绑定方法 // 类的方法,可以使用自己的成员 // 使用指针可以修改类的成员变量等 func (p *Person) Eat() { fmt.Println("使用 *Person 指针 修改前") fmt.Println(p.name + " is eating") p.name = "luenci" fmt.Println("使用 *Person 指针 修改后") fmt.Println(p.name + " is eating") } func (p Person) Eat2() { fmt.Println("使用 Person 不是指针 修改前") fmt.Println(p.name + " is eating") p.name = "luenci" fmt.Println("使用 Person 不是指针 修改后") fmt.Println(p.name + " is eating") } func main() { lynn := Person{ name: "lynn", age: 20, gender: "girl", } lynn.Eat() lynn.Eat2() } 类的继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package main import "fmt" type Human struct { name string sex string age int } type Student struct { hum Human // 包含 Human类型的变量 是嵌套类 school string } type Teacher struct { Human // 直接声明Human类型,没有定义变量 类继承 school string } // 类外面绑定方法 func (h *Human) Eat() { fmt.Println(h.name + " is eating") } func main() { st1 := Student{ hum: Human{ name: "lynn", sex: "girl", age: 20, }, school: "一中", } fmt.Println("st1", st1) fmt.Println("st1 name", st1.hum.name) t1 := Teacher{} t1.school = "一中" t1.name = "lynn" t1.sex = "girl" t1.age = 20 fmt.Println("t1", t1) fmt.Println("t1 name", t1.name) // 继承的时候虽然我们没有声明变量名称,但是默认自动会给类型创建一个同名字段 // 这是为了能在子类中操作父类,因为:子类父类可能出现同名字段 fmt.Println("t1 age", t1.Human.age) } 类成员访问权限(字段大小写)...

5 min · 2016 words · Luenci

管道和go程

管道和go程 goroutine(go程) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package main import ( "fmt" "time" ) func display(num int) { count := 1 for { fmt.Println("============> 这是子go程:", num, "当前count值", count) count++ } } func main() { // 启动子go程 for i := 0; i < 3; i++ { go display(i) } // 主go程 count := 1 for { fmt.Println("============> 这是主go程:", count) count++ time.Sleep(1 * time.Second) } } 提前退出go程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package main import ( "fmt" "runtime" "time" ) // GOEXIT ===> 提前退出go程 // return ===> 返回当前函数 // exit ===> 退出当前进程 func main() { go func() { func() { fmt.Println("子go程内部的函数!") //return // 退出当前函数 //os.Exit(-1) // 退出进程 runtime.Goexit() // 退出当前go程 }() fmt.Println("子go程结束!") }() // 主go程需要等待子go程退出 fmt.Println("主go程~") time.Sleep(5 * time.Second) fmt.Println("OVER!") } 无缓冲管道 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package main import ( "fmt" "time" ) /* 当通道在多个协程之间传输的是指向数据的指针是,且读写操作是由不同的协程操作,则需要提供额外的同步动作。 */ func main() { // 当涉及到多go程时,c语言使用互斥量,上锁来保持资源同步,避免资源竞争问题 // go语言更好的解决方案是管道、通道 // 使用通道不需要手动进行加锁 //sync.RWMutex{} // 创建管道 关键字 chan numChan := make(chan int) // 装数字的管道,无缓冲通道,未声明空间 //numChan := make(chan int, 10) // 有缓冲通道 // 创建两个go程,父写,子读 // 发现子go程没有发生资源抢夺 // 子go程1 go func() { for i := 0; i < 25; i++ { // 只能 <- 数据流向 data := <-numChan fmt.Println("子go程1 读取data", data) } }() // 子go程2 go func() { for i := 0; i < 25; i++ { data := <-numChan fmt.Println("子go程2 读取data", data) } }() // 父go程 for i := 0; i < 50; i++ { // 向管道中写入数据 numChan <- i fmt.Println("====> 主go程,写入数据", i) } time.Sleep(5 * time.Second) } ...

5 min · 2255 words · Luenci

consul服务发现

consul服务发现 Consul是由HashiCorp开发的一个支持多数据中心的分布式服务发现和键值对存储服务的开源软件,被大量应用于基于微服务的软件架构当中。 服务发现流程图 服务发现,也可以看做一个“服务”,是给“服务”提供服务的 服务发现种类 consul:常用于go-micro中 mdns:go-micro中默认的服务发现 etcd:k8s内嵌的服务发现 zookeeper:java中常用 Consul关键特性 服务发现:consul提供服务,服务端主动向consul发起注册。 健康检查:定时发送消息,类似于“心跳包”,保证客户端获取到的一定是健康的服务。 键值存储:consul提供,但常用于redis。 多数据中心:可以轻松加入集群。 Consul 参数 安装好 Consul 后,在启动程序之前,需要掌握一些配置参数,通过掌握这些参数,可以一次性的成功运行 Consul 服务器集群,常用的参数如下: 参数名称 用途 -server 此标志用于控制代理是运行于服务器/客户端模式,每个 Consul 集群至少有一个服务器,正常情况下不超过5个,使用此标记的服务器参与 Raft一致性算法、选举等事务性工作 -http-port=8500 consul自带的一个web访问端口,默认为8500 -client 表示 Consul 绑定客户端接口的IP地址,默认值为:127.0.0.1,当你有多块网卡的时候,最好指定IP地址,不要使用默认值 -bootstrap-expect 预期的服务器集群的数量,整数,如 -bootstrap-expect=3,表示集群服务器数量为3台,设置该参数后,Consul将等待指定数量的服务器全部加入集群可用后,才开始引导集群正式开始工作,此参数必须与 -server 一起使用 -data-dir 存储数据的目录,该目录在 Consul 程序重启后数据不会丢失,指定此目录时,应确保运行 Consul 程序的用户对该目录具有读写权限 -config-dir=XX 所有服务主动注册的配置文件 - node 当前服务器在集群中的名称,该值在整个 Consul 集群中必须唯一,默认值为当前主机名称 - bind Consul 在当前服务器侦听的地址,如果您有多块网卡,请务必指定一个IP地址(IPv4/IPv6),默认值为:0.0.0.0,也可用使用[::] ...

4 min · 2003 words · Luenci

json、结构体标签和rpc入门

json、结构体标签和rpc入门 json使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package main import ( "encoding/json" "fmt" "reflect" ) // 将 结构体 --> 字符串 编码 // 将 字符串 --> 结构体 解码 // 结构体的成员须大写,不然不参与编码 type Student struct { Name string Sex string Age int Score int } func main() { st1 := Student{ Name: "luenci", Sex: "man", Age: 22, Score: 99, } // 编码 序列化 encodeInfo, err := json.Marshal(st1) if err != nil { fmt.Println("序列化发生错误,error", err) return } fmt.Println(reflect.TypeOf(encodeInfo)) fmt.Println(string(encodeInfo)) // 解码 反序列化 var st2 Student if err := json.Unmarshal([]byte(encodeInfo), &st2); err != nil { fmt.Println("反序列化发生错误,", err) return } fmt.Println(st2.Name) } ...

3 min · 1380 words · Luenci

深入理解堆、栈、CPU密集型 和 I/O 密集型任务

关于堆、栈、CPU密集型 和 I/O 密集型知识 程序中的内存分配方式(c/c++) 1、栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其 操作方式类似于数据结构中的栈。 2、堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回 收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链。 3、全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的 全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另 一块区域。 - 程序结束后由系统释放。 4、文字常量区:常量字符串就是放在这里的。 程序结束后由系统释放 5、程序代码区:存放函数体的二进制代码。 python的堆栈解析 因为是动态语言**,python中的所有变量内容都存在堆(heap)中**,而变量名只是堆中内容的引用,存放在栈(stack)中,便于用户去间接操作堆中的数据。 堆与栈实际上是操作系统对进程占用的内存空间的两种管理方式,主要有如下几种区别: (1)管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏; (2)空间大小不同。每个进程拥有的栈的大小要远远小于堆的大小。理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB; (3)生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。 (4)分配方式不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由malloc函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由操作系统进行释放,无需我们手工实现。 (5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。 (6)存放内容不同。栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。 ...

6 min · 2614 words · Luenci