关于golang:k8s镜像一直failed-pull-images

通过流水线部署我的项目后,在负载重新部署的过程中,镜像始终都在尝试从新拉取镜像,然而都失败了: failed pull image Failed to pull image "registry.cn-shanghai.aliyuncs.com/xxxxxxxx:xxxxx": rpc error: code = Unknown desc = Error response from daemon: Get "https://registry.cn-shanghai.aliyuncs.com/v2/": dial tcp 139.196.71.17:443: i/o timeout 查看部署模板的配置,也看到了镜像的更新,然而实际上pod缺没有更新; 于是乎,尝试着在master节点被动docker pull镜像发现失常 然而转到了work节点pull镜像发现失败,ping百度失败 豁然开朗,nat网络被我上周关了,导致节点无法访问外网,从新给work节点配置了nat网络后,服务回复失常 本文由博客一文多发平台 OpenWrite 公布!

January 22, 2022 · 1 min · jiezi

关于golang:Go官方推出了Go-118的2个新教程

前言2022年1月14日,Go官网团队的Katie Hockman在Go官网博客网站上发表了一篇新文章,次要介绍了Go 1.18的2个新教程,波及Go泛型和Go Fuzzing。 自己针对Katie Hockman的原文做了一个翻译,以飨读者。 同时在本文最初,附上了对Go泛型官网教程的中文翻译,以及针对Go泛型的设计思维和最佳实际。 原文翻译谷歌Go团队Katie Hockman 2022.1.14 咱们很快就会公布Go 1.18版本,这个版本会引入一些新的概念。咱们曾经公布了2个官网教程来帮忙大家相熟这些新的feature。 第一篇教程是帮忙大家相熟Go泛型。这个教程会带着大家一步一步实现一个能解决多个类型的泛型函数,并且在代码里调用泛型函数。一旦你实现了泛型函数,你就会学到对于类型束缚(type constraint)的常识,并且在你的函数里用到它。同时,也倡议大家查阅最近GopherCon上Robert Greisemer和Ian Lance Taylor对于泛型的技术分享,能够学到更多对于Go泛型的常识。 第二篇教程是对于Go fuzzing的介绍。这个教程展现了如何利用Fuzzing来帮忙查找代码里的bug,带你一起利用Fuzzing来诊断和修复代码问题。同时,你也会在这个教程里写一些有bug的代码,利用Fuzzing来发现,修复和验证这些bug。特别感谢Beth Brown写了这篇教程。 Go 1.18 Beta 1版本上个月曾经公布了,大家能够从官网下载地址进行下载。 大家也能够查看Go 1.18残缺的公布清单。 和以前一样,如果你发现了任何问题,请在GitHub上提issue。 心愿大家能喜爱这2个教程,咱们期待2022年有更多美妙事件的产生。 后记自己针对Go泛型写了2篇通俗易懂的入门文章,一个是官网英文教程的中文翻译,一个是自己整顿的Go泛型设计思维和应用场景解析,倡议感兴趣的能够重点参考。 Go 泛型官网教程中文版本:官网教程:Go泛型入门Go 泛型设计思维和最佳实际解析:一文读懂Go泛型设计和应用场景近期,我也会针对Go Fuzzing写一篇技术分享文章,欢送大家关注。 开源地址GitHub: https://github.com/jincheng9/... 公众号:coding进阶 集体网站:https://jincheng9.github.io/ Referenceshttps://github.com/jincheng9/...https://go.dev/doc/tutorial/g...https://jincheng9.github.io/p...https://www.youtube.com/watch...

January 22, 2022 · 1 min · jiezi

关于golang:Go语言通用开发框架Ngo开源啦

网易传媒在2020年底开始尝试应用Go语言做业务开发,并在2021年应用Go语言重构外围业务,目前超过一半的业务都曾经重构为Go语言,并在线上提供服务。 1、为什么要用Go语言Go语言于2009年11月正式发表推出,它是Google开发的一种动态强类型、编译型、并发型、并具备垃圾回收性能的编程语言,它的个性包含: 编译速度快语法简略像动静语言一样开发资源耗费少为并发IO而生可运维性好与C/C++兼容对立而齐备的工具集网易传媒的次要开发语言是Java,在业务全副接入容器后,在线业务也面临着以下一些问题: 在线业务内存使用量偏高:传媒次要开发语言是Java,应用SpringBoot框架,起码应用2G内存,广泛内存使用量都在4G以上,还有8G、16G、32G等内存应用的利用。在线业务编译速度和启动速度偏慢:应用maven编译、打包、打镜像、传镜像都比拟耗时,拖慢了整个CI的流程。占用空间较大:因为应用Java,JVM在镜像实例都须要上百兆(400M以上)的空间,拉取,上传都比拟耗时。网易传媒于2020年将外围业务全副迁入容器,在容器和微服务的大背景下,利用的小而快显得就分外的重要,Go语言就比拟适宜于咱们的需要,目前曾经有很多互联网厂商都在踊跃推动Go语言的利用,于是,网易传媒在2020年底开始尝试Go语言的摸索,并在2021年应用Go语言重构外围业务,目前超过一半的业务都曾经重构为Go语言,并在线上提供服务。 2、Ngo是什么在传媒技术团队中推广Go语言,亟需一个Web框架提供给业务开发共事应用,内含业务开发罕用库,防止反复造轮子影响效率,并且须要无感知的主动监控数据上报,能在框架层面反对业务的优雅高低线、对云原生监控的反对等,于是就孕育出ngo框架。 因为Go的开源Web框架没有相似Spring Boot大而全的,而最大的框架也是很受用户欢送的框架是Beego,为什么没有间接应用Beego呢?次要有以下几个起因: HTTP Server的性能不现实不足大量业务所需库,比方kafka、redis、rpc、分布式锁等,如果在其根底上开发不如从零抉择更适宜的库大部分库无奈注入回调函数若干模块如ORM不够好用基于以上的起因,传媒外部孕育出了ngo框架,次要指标如下: 提供比原有Java框架更高的性能和更低的资源占用率尽量为业务开发者提供所需的全副工具库嵌入云原生监控,主动上传监控数据嵌入全链路监控,提供规范的opentracering协定,和第三方的全链路监控零碎联合(Jaeger、Zipkin)主动加载配置和初始化程序环境,开发者能间接应用各种库与线上的健康检查、运维接口等运行环境匹配,无需用户手动开发配置ngo防止反复造轮子,所有模块都是在多个开源库中比照并筛选其一,而后减少局部必须性能,整个架构如下图所示:Ngo框架为业务抉择并包装了用到的中间件和根底服务,让业务能够疾速的进入到业务开发的阶段,省去了钻研和比拟一些根底组件的工夫,大大节俭了业务的开发周期。 3、疾速开始让咱们从一个最简略的HelloWorld开始Ngo之旅吧 首先,将代码从github上clone下来 git clone https://github.com/NetEase-Media/ngo.git其次,进入sample目录 cd ./ngo/examples/quickstart查看代码如下: package main import ("context" "github.com/NetEase-Media/ngo/adapter/log""github.com/NetEase-Media/ngo/adapter/protocol""github.com/NetEase-Media/ngo/server""github.com/gin-gonic/gin") func main() { s := server.Init() s.PreStart = func() error { log.Info("do pre-start...")return nil } s.PreStop = func(ctx context.Context) error { log.Info("do pre-stop...")return nil } s.AddRoute(server.GET, "/hello", func(ctx *gin.Context) { ctx.JSON(protocol.JsonBody("hello")) }) s.Start()}查看yaml配置如下: service: appName: ngo-demo clusterName: ngo-demo-local运行以下命令,最简略的服务便启动了 go run . -c ./app.yamlSo Cool!更多示例,咱们能够进入examples目录查看。Ngo拜访地址如下:Ngo GitHub

January 21, 2022 · 1 min · jiezi

关于golang:golangleetcode初级验证回文串字符串转换整数

第一题 验证回文串题目信息给定一个字符串,验证它是否是回文串,只思考字母和数字字符,能够疏忽字母的大小写。 阐明:本题中,咱们将空字符串定义为无效的回文串。   示例 1: 输出: "A man, a plan, a canal: Panama"输入: true解释:"amanaplanacanalpanama" 是回文串示例 2: 输出: "race a car"输入: false解释:"raceacar" 不是回文串  提醒: 1 <= s.length <= 2 * 105字符串 s 由 ASCII 字符组成 解题思路依据示例显然,验证是否是回文串之前,因为 只思考字母和数字字符,能够疏忽字母的大小写所以对于给定的字符串,咱们应该 提取出字符串中属于字符和数字的局部疏忽其余的符号而后咱们只需验证提取出的字符串是否是回文串就行了 代码func isPalindrome(s string) bool { if len(s)==1{ return true } var ss []byte for i, n := range s { if n <= 'Z' && n >= 'A' { ss = append(ss, s[i]+32) } if n >= 'a' && n <= 'z' || n >= '0' && n <= '9' { ss = append(ss, s[i]) } } if ss==nil {return true} for i := 0; i <= len(ss)/2; i++ { if ss[i] != ss[len(ss)-i-1] { return false } } return true}复杂度剖析工夫复杂度:O(∣s∣),其中 ∣s∣ 是字符串 ss 的长度。 ...

January 21, 2022 · 2 min · jiezi

关于golang:Golang-多种配置文件解析

Golang 配置文件相干操作本文以读取数据库配置文件为例1、JSON 文件package main/* 解析 json 格局的配置文件文件内容如下:{ "type": "json", "postgres": { "host": "localhost", "port": 5432, "username": "postgres", "password": "postgres", "dbname": "bubble" }}*/import ( "encoding/json" "fmt" "io/ioutil" "os")// 定义第一级配置文件的构造体type Config struct { Type string Postgres DbConf // 数据类型为第二级配置文件的构造体名称}// 定义第二级配置文件的构造体 留神数据类型type DbConf struct { Host string `json:"host"` Port uint `json:"port"` Username string `json:"username"` Password string `json:"password"` DbName string `json:"dbname"`}// 定义配置文件构造体type JsonStruct struct {}// 创立配置文件的构造函数func NewJsonStruct() *JsonStruct { return &JsonStruct{}}// 加载配置文件func (jt *JsonStruct) Load(filename string, v interface{}) { // 读取配置文件 data, err := ioutil.ReadFile(filename) if err != nil { return } // 解析配置文件 err = json.Unmarshal(data, v) if err != nil { return }}func main() { JsonParse := NewJsonStruct() v := Config{} // 获取配置文件门路 osGwd, _ := os.Getwd() confPath := osGwd + "/conf_json.json" // 加载配置文件 JsonParse.Load(confPath, &v) fmt.Printf("配置文件的类型为 %s \n", v.Type) fmt.Printf("PG 数据库的配置为 %s \n", v.Postgres)}2、YAML 文件(举荐)package main/*解析 yaml 格局的配置文件文件内容如下:database: postgres: host: localhost port: 5432 username: postgres password: postgres dbname: bubble} */import ( "fmt" "gopkg.in/yaml.v2" "io/ioutil" "os")type YamlStruct struct {}func NewYamlStruct() *YamlStruct { return &YamlStruct{}}type YamlConfig struct { DataBase DataBase `yaml:"database"`}type DataBase struct { PgConf PgConf `yaml:"postgres"`}type PgConf struct { Host string `yaml:"host"` Port string `yaml:"port"` Username string `yaml:"username"` Password string `yaml:"password"` DbName string `yaml:"dbname"`}func (yam *YamlStruct) Load(filename string, v interface{}) { data, err := ioutil.ReadFile(filename) if err != nil { panic(err.Error()) } err = yaml.Unmarshal(data, v) if err != nil { panic(err.Error()) }}func main() { YamlStruct := NewYamlStruct() v := YamlConfig{} osGwd, _ := os.Getwd() confPath := osGwd + "/conf_yaml.yaml" YamlStruct.Load(confPath, &v) fmt.Printf("配置文件的数据为 %s \n", v.DataBase)}3、INI 文件package main/* 解析 ini 格局的配置文件文件内容如下:mode=debug[postgres]host=localhostport=5432username=postgrespassword=postgresdbname=bubble */import ( "fmt" "github.com/go-ini/ini" "os")//type Postgres struct {// Host string// Port uint// Username string// Password string// DbName string//}func main() { osGwd, _ := os.Getwd() confPath := osGwd + "/conf_ini.ini" config, err := ini.Load(confPath) if err != nil { panic(err.Error()) } // 能够间接读取配置,并设置默认值 mode := config.Section("").Key("mode").MustString("debug") fmt.Println(mode) postgres, err := config.GetSection("postgres") if err != nil { panic(err.Error()) } // 可通过 Key 去取值 fmt.Println(postgres.Key("host")) // localhost fmt.Println(postgres.Keys()) // [localhost 5432 postgres postgres bubble] fmt.Println(postgres.KeyStrings()) // [host port username password dbname]}

January 21, 2022 · 2 min · jiezi

关于golang:golangleetcode初级字符串中的第一个唯一字符amp有效的字母异位词

第一题 字符串中的第一个惟一字符题目信息给定一个字符串,找到它的第一个不反复的字符,并返回它的索引。如果不存在,则返回 -1。   示例: s = "leetcode"返回 0 s = "loveleetcode"返回 2  提醒:你能够假设该字符串只蕴含小写字母。 解题思路对于这道题,最暴力的办法天然是: 对于字符串的每个字符,都查找一遍字符串,若找到雷同的字符,则开始查找下一个字符;若找不到雷同的字符,则返回该字符的索引。 暴力解法简略易懂的同时,也进行了大量的无意义操作,若惟一字符位于字符串尾部,则该算法的计算量将异样宏大。算法的工夫复杂度为O(n^2) 对此,咱们思考引入新的数据结构辅助实现对字符串的查问,即哈希表 哈希表是一种奇妙并且实用的数据结构。它是一个无序的key/value对的汇合,其中所有的key都是不同的,而后通过给定的key能够在常数工夫复杂度内检索、更新或删除对应的value。援用在Go语言中,一个map就是一个哈希表的援用,map类型能够写为map[K]V,其中K和V别离对应key和value。map中所有的key都有雷同的类型,所有的value也有着雷同的类型,然而key和value之间能够是不同的数据类型。其中K对应的key必须是反对==比拟运算符的数据类型,所以map能够通过测试key是否相等来判断是否曾经存在。详见https://haicoder.net/golang/g... 代码func firstUniqChar(s string) int { m:= make(map[rune]int, 26) for _, ch := range s { m[ch]++ } for i, ch := range s { if m[ch] == 1 { return i } } return -1}复杂度剖析工夫复杂度:O(n),其中 n 是字符串 s 的长度。咱们须要进行两次遍历。 空间复杂度:O(∣∣),其中 是字符集,在本题中 s 只蕴含小写字母,因而 ∣∣≤26。咱们须要 O(∣∣) 的空间存储哈希映射。 小优化浏览官网代码 func firstUniqChar(s string) int { cnt := [26]int{} for _, ch := range s { cnt[ch-'a']++ } for i, ch := range s { if cnt[ch-'a'] == 1 { return i } } return -1}作者:LeetCode-Solution链接:https://leetcode-cn.com/problems/first-unique-character-in-a-string/solution/zi-fu-chuan-zhong-de-di-yi-ge-wei-yi-zi-x9rok/起源:力扣(LeetCode)著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。咱们能够看到,官网在应用哈希表时,将读到的字符减去字符a的码值再进行查表通过比照尝试,发现这样能够大幅度缩小执行工夫 ...

January 20, 2022 · 2 min · jiezi

关于golang:kratos线上开源年会它来啦~

各位 V2EX 社区的敌人们大家好呀,咱们是 Go 微服务框架 Kratos 的维护者团队,咱们的我的项目地址是 https://github.com/go-kratos/... 在本周四,咱们将在 B 站直播咱们的线上年会。 直播工夫:2022 年 1 月 20 号 周四 20:30直播间地址: https://live.bilibili.com/241...B 站帐号: https://space.bilibili.com/18... 从 2021 年 2 月份,github 上 Kratos v2 版本第一次代码提交,到功能模块的探讨,批改,测试,最终定稿,曾经过来了 11 个月,在社区各位搭档的奉献下,Kratos v2 曾经从 2.0.0 alpha1 版本迭代到了 2.1.4 版本,具备了微服务框架的残缺能力,在此感激各位社区搭档的奉献。 值此新春之际,咱们决定举办线上的首次 Kratos 开源直播年会,邀请了毛剑,谢孟军,曹春晖,曹国梁,陈志辉等业界大佬一起聊聊天,总结在过来一年里社区小伙伴们对 Kratos 我的项目做出的巨大贡献,并且将会给对 kratos 我的项目做出巨大贡献的小伙伴颁发贡献者证书。另外咱们会对 2022 年 Kratos 我的项目做出整体规划,Kratos 将会深耕基于 Istio 和 xDS 协定的微服务治理方向,实现面向未来的微服务治理能力。 在直播中,咱们还有好礼送出,欢送到时候来看看!

January 19, 2022 · 1 min · jiezi

关于golang:golangleetcode初级反转字符串整数反转

第一题 反转字符串题目信息编写一个函数,其作用是将输出的字符串反转过去。输出字符串以字符数组 s 的模式给出。 不要给另外的数组调配额定的空间,你必须原地批改输出数组、应用 O(1) 的额定空间解决这一问题。   示例 1: 输出:s = ["h","e","l","l","o"]输入:["o","l","l","e","h"]示例 2: 输出:s = ["H","a","n","n","a","h"]输入:["h","a","n","n","a","H"]  提醒: 1 <= s.length <= 105s[i] 都是 ASCII 码表中的可打印字符 解题思路很简略的思路,遍历二分之一的数组,让前半部分与后半局部一一替换 代码func reverseString(s []byte) { var n int=len(s)-1 for i:=0;i<=n/2;i++{ s[i],s[n-i]=s[n-i],s[i] }}复杂度剖析工夫复杂度:O(N),其中 N 为字符数组的长度。一共执行了 N/2 次的替换。空间复杂度:O(1)。只应用了常数空间来寄存若干变量。 第二题 整数反转题目信息给你一个 32 位的有符号整数 x ,返回将 x 中的数字局部反转后的后果。 如果反转后整数超过 32 位的有符号整数的范畴 [−2^31,  2^31 − 1] ,就返回 0。 假如环境不容许存储 64 位整数(有符号或无符号)。  示例 1: 输出:x = 123输入:321示例 2: 输出:x = -123输入:-321示例 3: ...

January 19, 2022 · 1 min · jiezi

关于golang:对控制反转和依赖注入的突然顿悟

管制反转和依赖注入的概念在网络上有大量的解释,很多都十分的具体,但对我来说过多的解释,容易把我绕来绕去,昨天听大佬的课,忽然清晰地顿悟了。心愿通过简略的形容,记录我的了解。管制反转(IOC):上面通过两张简略的图,理解一下管制反转的思维,咱们假如本人当初想吃回锅肉! 首先,咱们能够本人炒一道合乎本人口味的回锅肉,能够多加肉!而后咱们就把它吃掉!!这种状况下回锅肉炒成什么样由咱们本人管制。 ok!第二天咱们又想吃回锅肉了,然而有点懒,咱们抉择点外卖。 这回咱们叫的外卖,那么商家将回锅肉炒成什么样并不是咱们能决定的,也就是回锅肉炒成什么样不是咱们可能管制的,咱们就是拿到外卖吃。 很显著回锅肉的控制权从本人变成了他人,这种就叫做管制反转。 在面向对象编程中,每当咱们要new一个新的对象的时候,也就是咱们所说的实例化对象,个别状况下都是被动new一个新的对象。在IOC思维中,咱们通常把实例化的工作交给他人,也就是本人被动的实例化变为被动的实例化,本人对实例的控制权被他人代替了,即控制权反转了。咱们个别将实例化的工作交给IOC容器对立治理生命周期。 依赖注入(DI):依赖注入是实现管制反转思维的一种形式,其想法就是在对象或属性被初始化的时候,将它所须要的依赖从内部注入进来,并不需要本人外部实例化依赖。 咱们通过一段代码(Go语言)来看看为什么注入的依赖合乎管制反转的思维。 type Player struct { name string}type GameRoom struct { player *Player}//这里咱们就将GameRoom依赖的Player从内部注入进来//Player的实例化也交给了内部,所以对于Player的控制权反转了。func NewGameRoom(player *Player) *GameRoom { return &GameRoom{player: player}}很多状况下咱们会应用接口注入,而接口的实例化就归内部(通常是IOC容器),不仅合乎多态,更加体现了依赖倒置准则(单方都应该依赖一个形象)。 type Player interface { GetName() string}type GameRoom struct { player Player}//Player通过接口的形式注入进来,咱们毋庸//关系Player如何实现的,这样连注入的依赖//也变成形象的func NewGameRoom(player Player) *GameRoom { return &GameRoom{player: player}}这种形式益处颇多,比方更容易被单元测试、代码耦合性升高等等等等。心愿这篇最简略的解释,可能使咱们更快地了解IOC和DI的概念。

January 19, 2022 · 1 min · jiezi

关于golang:GoGo-语言基础拾遗一

工作区和 GOPATH在装置 Go 过程中须要配置 3 个环境变量:GOROOT、GOPATH 和 GOBIN。 GOROOT:Go 语言的装置根目录门路,也就是 Go 语言的装置门路。GOPATH:若干工作区目录的门路。使咱们本人定义的工作空间。GOBIN:Go 程序生成的可执行文件的门路。设置 GOPATH 有什么意义?咱们能够把 GOPATH 简略了解成 Go 语言的工作目录,它的值是一个或者多个目录门路,每个目录门路都代表着 Go 语言的一个工作区。 Go 语言源码的组织形式是怎么的?根本组织单位是代码包。代码包的名称个别与源码文件所在目录同名。如果不同名,则在构建、装置的过程中以代码包的名称为准。一个代码包能够蕴含任意个以 .go 扩展名的源码文件,这些源码文件申明属于同一个代码包。每个代码包都有导入门路。在工作区,代码包导入门路,理论是 src 目录到该代码包的相对路径。源码装置后,各文件如何存储?源码文件存储在 src 子目录下。在装置后,产生了归档文件(以 .a 扩展名的文件),放进 pkg 子目录。在装置后,产生了可执行文件,放进 bin 子目录。构建和装置 GO 程序的过程是怎么的?构建命令 go build 如果构建的是库源码文件,那么操作后的后果只会存储在临时文件中。这里的构建的作用只是检查和验证。如果构建的是命令源码文件,操作的后果文件会存储在源码文件所在目录。装置命令 go install 安装操作会先执行构建,而后还会进行链接操作,并且把后果文件搬运到指定目录。如果装置的是库源码文件,那么后果文件会被搬运到它所在工作区的 pkg 目录下的某个子目录中。如果装置的是命令源码文件,那么后果文件会被搬运到它所在工作区的 bin 目录中,或者环境变量 GOBIN 指向的目录中。

January 18, 2022 · 1 min · jiezi

关于golang:golangleetcode初级加一移动零

第一题 加一题目信息给定一个由 整数 组成的 非空 数组所示意的非负整数,在该数的根底上加一。 最高位数字寄存在数组的首位, 数组中每个元素只存储单个数字。 你能够假如除了整数 0 之外,这个整数不会以零结尾。   示例 1: 输出:digits = [1,2,3]输入:[1,2,4]解释:输出数组示意数字 123。示例 2: 输出:digits = [4,3,2,1]输入:[4,3,2,2]解释:输出数组示意数字 4321。示例 3: 输出:digits = [0]输入:[1]  提醒: 1 <= digits.length <= 1000 <= digits[i] <= 9 解题思路对于一个数加一,有以下几种状况 1.没有产生进位2.一直产生进位,直到某一位不须要进位的时候停下回到第一种状况3.数字首位为9且须要进位,则应将数组长度加一 因而咱们能够将进位过程写入函数中,在有须要的时候能够随时调用 代码func inc(digits []int,n int) []int{ if digits[n]<9{ digits[n]++ return digits }else{ if n==0{ digits=append(digits,0) copy(digits[1:len(digits)-1],digits[:len(digits)-2]) digits[0]=1 digits[1]=0 return digits }else { digits[n] = 0 return inc(digits, n-1) } }}func plusOne(digits []int) []int { n:=len(digits)-1 return inc(digits,n)}复杂度剖析工夫复杂度:O(n) 最坏状况为数组每个元素都产生进位,进行了n次函数调用空间复杂度:O(n^2) 每次函数调用须要数组长度的空间显然,选择函数递归调用本质是就义空间换取工夫的做法 ...

January 18, 2022 · 1 min · jiezi

关于golang:golangleetcode初级删除排序数组中的重复项买卖股票的最佳时机-II

第一题 删除排序数组中的反复项题目信息给你一个有序数组 nums ,请你 原地 删除反复呈现的元素,使每个元素 只呈现一次 ,返回删除后数组的新长度。 不要应用额定的数组空间,你必须在 原地 批改输出数组 并在应用 O(1) 额定空间的条件下实现。   阐明: 为什么返回数值是整数,但输入的答案是数组呢? 请留神,输出数组是以「援用」形式传递的,这意味着在函数里批改输出数组对于调用者是可见的。 你能够设想外部操作如下: // nums 是以“援用”形式传递的。也就是说,不对实参做任何拷贝int len = removeDuplicates(nums); // 在函数里批改输出数组对于调用者是可见的。// 依据你的函数返回的长度, 它会打印出数组中 该长度范畴内 的所有元素。for (int i = 0; i < len; i++) {    print(nums[i]);} 示例 1: 输出:nums = [1,1,2]输入:2, nums = [1,2]解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被批改为 1, 2 。不须要思考数组中超出新长度前面的元素。示例 2: 输出:nums = [0,0,1,1,1,2,2,3,3,4]输入:5, nums = [0,1,2,3,4]解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被批改为 0, 1, 2, 3, 4 。不须要思考数组中超出新长度前面的元素。  ...

January 17, 2022 · 2 min · jiezi

关于golang:golangleetcode初级旋转数组存在重复元素

第一题 旋转数组题目信息给你一个数组,将数组中的元素向右轮转 k 个地位,其中 k 是非正数。   示例 1: 输出: nums = [1,2,3,4,5,6,7], k = 3输入: [5,6,7,1,2,3,4]解释:向右轮转 1 步: [7,1,2,3,4,5,6]向右轮转 2 步: [6,7,1,2,3,4,5]向右轮转 3 步: [5,6,7,1,2,3,4]示例 2: 输出:nums = [-1,-100,3,99], k = 2输入:[3,99,-1,-100]解释: 向右轮转 1 步: [99,-1,-100,3]向右轮转 2 步: [3,99,-1,-100]  提醒: 1 <= nums.length <= 105-231 <= nums[i] <= 231 - 10 <= k <= 105  进阶: 尽可能想出更多的解决方案,至多有 三种 不同的办法能够解决这个问题。你能够应用空间复杂度为 O(1) 的 原地 算法解决这个问题吗? 解题思路在go语言圣经的slice篇中介绍了这样一个例子 上面的reverse函数在原内存空间将[]int类型的slice反转,而且它能够用于任意长度的slice。// reverse reverses a slice of ints in place.func reverse(s []int) { ...

January 17, 2022 · 2 min · jiezi

关于golang:Google-大佬们为什么要开发-Go-这门新语言

大家好,我是煎鱼。 大家平时都是在用 Go 语言,那以往曾经有了 C、C++、Java、PHP。Google 的大佬们为什么还要再开发一门新的语言呢? 难不成是造轮子,其余语言不香吗? 背景Go 编程语言构思于 2007 年底,构思的目标是:为了解决在 Google 开发软件基础设施时遇到的一些问题。 图上三位是 Go 语言最后的设计者,功力都十分的深厚,按序从左起别离是: Robert Griesemer:参加过 Google V8 JavaScript 引擎和 Java HotSpot 虚拟机的研发。Rob Pike:Unix 操作系统晚期开发者之一,UTF-8 创始人之一,Go 语言吉祥物设计者是 Rob Pike 的媳妇。Ken Thompson:图灵奖得主,Unix 操作系统晚期开发者之一,UTF-8 创始人之一,C 语言(前身 B 语言)的设计者。遇到的问题已经在晚期的采访中,Google 大佬们反馈感觉 "编程" 太麻烦了,他们很不喜爱 C++,对于当初工作所用的语言和环境感觉比拟丧气,充斥着许多不怎么好用的个性。 具体遭逢到的问题。如下: 软件简单:多核处理器、网络系统、大规模计算集群和网络编程模型所带来的问题只能临时绕开,没法侧面解决。软件规模:软件规模也产生了变动,明天的服务器程序由数千万行代码组成,由数百甚至数千名程序员进行工作,而且每天都在更新(据闻 Go 就是在等编译的 45 分钟中想进去的)。编译耗时:在大型编译集群中,构建工夫也缩短到了几分钟,甚至几小时。设计目标为了实现上述指标,在既有语言上革新的话,须要解决许多根本性的问题,因而须要一种新的语言。 这门新语言须要合乎以下需要: 目标:设计和开发 Go 是为了使在这种环境下可能进步工作效率。设计:在 Go 的设计上,除了比拟出名的方面:如内置并发和垃圾收集。还思考到:严格的依赖性治理,随着零碎的倒退,软件架构的适应性,以及逾越组件之间边界的健壮性。这门新语言就是当初的 Go。 Go 在 GoogleGo 是 Google 设计的一种编程语言,用于帮忙解决谷歌的问题,而 Google 的问题很大。 Google 整体的应用软件很宏大,硬件也很宏大,有数百万行的软件,服务器次要是 C++ 语言,其余局部则是大量的 Java 和 Python。 ...

January 17, 2022 · 1 min · jiezi

关于golang:grpc-源码阅读之-balancer

BalancergRPC balancer 背景接着上篇《gRPC 插件式编程之Resolver》,gRPC 将 target 解析为 resolver.Target 后,通过 resolver.Builder.Build 办法调用resolver.ClientConn.UpdateState(State) error 办法,该办法做了哪些事件呢,咱们本篇接着看源码往下走。 UpdateStateUpdateState 的调用会调用 grpc.ClientConn.updateResolverState 办法,该办法次要做了如下工作: ServiceConfig 解决BalancerWrapper 创立调用 balancer.updateClientConnState 办法 执行负载平衡逻辑更新func (cc *ClientConn) updateResolverState(s resolver.State, err error) error { ... cc.maybeApplyDefaultServiceConfig(s.Addresses) ... cc.applyServiceConfigAndBalancer(sc, configSelector, s.Addresses) ... // reference: balancer_conn_wrappers.go:164 // bw.updateClientConnState -> ccBalancerWrapper.updateClientConnState bw.updateClientConnState(&balancer.ClientConnState{ResolverState: s, BalancerConfig: balCfg}) ...}舒适提醒这里先以搞懂 gRPC 主流程思路为主,不扣太细节的货色,比方一些 GRPCLB 解决、error解决,ServiceConfigSelector 解决等能够查看源码。 bw.updateClientConnState 调用实质是 ccBalancerWrapper.updateClientConnState而 ccBalancerWrapper.updateClientConnState 就做了一件事件,调用 balancer.Balancer.UpdateClientConnState 办法 func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error { ccb.balancerMu.Lock() defer ccb.balancerMu.Unlock() return ccb.balancer.UpdateClientConnState(*ccs)}到这里,咱们想看 balancer 源码逻辑有两种路径 ...

January 17, 2022 · 6 min · jiezi

关于golang:golangleetcode初级只出现一次的数字两个数组的交集Ⅱ

第一题 只呈现一次的数字题目给定一个非空整数数组,除了某个元素只呈现一次以外,其余每个元素均呈现两次。找出那个只呈现了一次的元素。 阐明: 你的算法应该具备线性工夫复杂度。 你能够不应用额定空间来实现吗? 示例 1: 输出: [2,2,1]输入: 1示例 2: 输出: [4,1,2,1,2]输入: 4 解题思路对于本题,初始解题思路是遍历数组,通过某个容器判断元素是否屡次呈现。但题目要求了应用额定空间实现,那么咱们只能想方法在遍历数组的过程中通过运算消去雷同的元素,借鉴评论区,咱们找到了这样的一个运算 异或也叫半加运算,其运算法令相当于不带进位的二进制加法其运算法令为 aba⊕b000011101110故对于任意的数a,有任何数和 00 做异或运算,后果依然是原来的数,即a⊕0=a。任何数和其本身做异或运算,后果是 00,即a⊕a=0。 在golang语言中^运算符有两个性能 1、作为二元运算符 ^作二元运算符就是异或,包含符号位在内,雷同为0,不雷同为1 规定:1^1 =0, 0^0=0,1^0=1,0^1=1 2、作为一元运算符 ^作一元运算符示意是按位取反,包含符号位在内规定:1=0,0=1 复杂度剖析工夫复杂度:O(n),其中 n 是数组长度。只须要对数组遍历一次。空间复杂度:O(1)。 代码func singleNumber(nums []int) int { for _,i:=range nums[1:]{ nums[0]=nums[0]^i } return nums[0]}第二题题目给你两个整数数组 nums1 和 nums2 ,请你以数组模式返回两数组的交加。返回后果中每个元素呈现的次数,应与元素在两个数组中都呈现的次数统一(如果呈现次数不统一,则思考取较小值)。能够不思考输入后果的程序。   示例 1: 输出:nums1 = [1,2,2,1], nums2 = [2,2]输入:[2,2]示例 2: 输出:nums1 = [4,9,5], nums2 = [9,4,9,8,4]输入:[4,9]  提醒: 1 <= nums1.length, nums2.length <= 10000 <= nums1[i], nums2[i] <= 1000  ...

January 17, 2022 · 1 min · jiezi

关于golang:Go-Errors-详解

原文地址:Go Errors详解 Golang 中的错误处理和 PHP、JAVA 有很大不同,没有 try...catch 语句来处理错误。因而,Golang 中的错误处理是一个比拟有争议的点,如何更好的 了解 和 解决 错误信息是值得去深入研究的。 Go 内置 errorsGo error 是一个接口类型,它蕴含一个 Error() 办法,返回值为 string。任何实现这个接口的类型都能够作为一个谬误应用,Error 这个办法提供了对谬误的形容: // http://golang.org/pkg/builtin/#error// error 接口的定义type error interface { Error() string}// http://golang.org/pkg/errors/error.go// errors 构建 error 对象type errorString struct { s string}func (e *errorString) Error() string { return e.s}error 是一个接口类型,它蕴含一个 Error() 办法,返回值为 string。只有实现这个 interface 都能够作为一个谬误应用,Error 这个办法提供了对谬误的形容。 error 创立error 的创立形式有两种办法: 1. errors.New()// New returns an error that formats as the given text.// Each call to New returns a distinct error value even if the text is identical.func New(text string) error { return &errorString{text}}Q:为何 errors.New() 要返回指针? ...

January 17, 2022 · 3 min · jiezi

关于golang:彻底弄懂WebSocket

前言在WebSocket呈现之前,前端和后端交互通常应用Ajax进行HTTP API 通信,然而若有实时性要求的我的项目,如聊天室或游戏中PVP对战或推送音讯等场景,须要前端定时向后端轮询,然而轮询过快可能导致后端服务压力过大,轮询过慢可能导致实时性不高。WebSocket则为浏览器/客户端和服务器和服务端提供了双向通信的能力,放弃了客户端和服务端的长连贯,反对双向推送音讯 什么是WebSocketWebSocket和HTTP一样属于OSI网络协议中的第七层,反对双向通信,底层连贯采纳TCP。WebSocket并不是全新的协定,应用时须要由HTTP降级,故它应用的端口是80(或443,有HTTPS降级而来),WebSocket Secure (wss)是WebSocket (ws)的加密版本,下图是WebSocket的建设和通信示意图。 须要特地留神的有 疾速入门(注:本文应用golang语言,不过原理都是想通的) 应用Go语言,通常有两种形式,一种是应用Go 语言内置的net/http 库编写WebSocket服务器,另一种是应用gorilla封装的Go语言的WebSocket语言官网库,Github地址:gorilla/websocket.(注,当然还有其余的Websocket封装库,目前gorilla这个比拟罕用),gorilla库提供了一个聊天室的demo,本文将以这个例子上手入门. 1. 启动服务gorilla/websocket 的聊天室的README.md $ go get github.com/gorilla/websocket$ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/chat`$ go run *.go2. 关上浏览器页面,输出http://localhost:8080/ 作为示例,我关上了两个页面,如下图所示 在右边输出hello,myname is james,两个窗口同时显示了这句话,F12关上调试窗口,在network那个tab下的ws 中右边的data有刚输出的上行和上行音讯,而左边只有上行音讯,阐明音讯的确的确通过右边的连贯发送到服务端,并进行了播送给所有的客户端。 3. 如何建设连贯同样还是上述的F12调试窗口中的network tab 下的ws,关上申请头 <img src="http://tva1.sinaimg.cn/large/8dfd1ceegy1gyecwl7xxrj211o0oigwp.jpg" alt="image.png" style="zoom: 25%;" /><img src="http://tva1.sinaimg.cn/large/8dfd1ceegy1gyeczxc6ukj20we0powna.jpg" alt="image.png" style="zoom:25%;" /> 申请音讯: GET ws://localhost:8080/ws HTTP/1.1Host: localhost:8080Connection: UpgradePragma: no-cacheCache-Control: no-cacheUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36Upgrade: websocketOrigin: http://localhost:8080Sec-WebSocket-Version: 13Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Cookie: Goland-cd273d2a=102d1f43-0418-4ea3-9959-2975794fdfe3Sec-WebSocket-Key: 2e1HXejEZhjvYEEVOEE79g==Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits其中GET申请是ws://结尾,区别于HTTP /pathUpgrade: websocket和Connection: Upgrade标识降级HTTP为WebSocketSec-WebSocket-Key: 2e1HXejEZhjvYEEVOEE79g==其中2e1HXejEZhjvYEEVOEE79g==为6个随机字节的base64用于标识一个连贯,并非用于加密Sec-WebSocket-Version: 13指定了WebSocket的协定版本应答音讯: ...

January 16, 2022 · 5 min · jiezi

关于golang:Golang连接MySQL数据库并进行简单查询

1、装置驱动go get github.com/go-sql-driver/mysql2、导入须要的库import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql")3、连贯数据库func main() { //"用户名:明码@[连贯形式](主机名:端口号)/数据库名" db, _ := sql.Open("mysql", "root:123456@(localhost)/world") // 设置连贯数据库的参数 defer db.Close() //敞开数据库 err := db.Ping() //连贯数据库 if err != nil { fmt.Println("数据库连贯失败") //连贯失败 return } else { fmt.Println("数据库连贯胜利") //连贯胜利 }}4、查问表rows, _ := db.Query("select * from city") //获取city表所有数据 var ID, Population int var Name, CountryCode, District string for rows.Next() { //循环显示所有的数据 rows.Scan(&ID, &Name, &CountryCode, &District, &Population) fmt.Println(ID, "--", Name, "--", CountryCode, "--", District, "--", Population) }查问截图: ...

January 16, 2022 · 1 min · jiezi

关于golang:深入浅出-Golang-资源嵌入方案gobindata篇

上篇文章中,咱们讲到了 Golang 原生的资源嵌入计划,本篇咱们先来聊聊开源实现中排行中靠前的计划:go-bindata。 之所以先聊这个计划,是因为尽管它目前的热度和受欢迎水平并不是最高的,然而它的影响范畴和工夫综合来看,是比拟大的,而且在实现和应用上,因为历史起因,它的硬分叉版本也是最多的,状况最为简单。 各个开源我的项目之间的渊源先来聊聊这类开源我的项目之间的渊源吧。目前我的项目中会用到的 go-bindata 的我的项目次要有四个,别离是: (1500+ stars)https://github.com/go-bindata/go-bindata(840+ stars)https://github.com/elazarl/go-bindata-assetfs(630+ stars)https://github.com/jteeuwen/go-bindata(280+ stars)https://github.com/kevinburke/go-bindata这些我的项目的独特起源是 jteeuwen/go-bindata 这个我的项目,它的第一行代码提交于 十年前的2011年6月。 然而在 2018 年2月7日,作者因为一些起因删除了他创立的所有仓库,随后这个账号也被弃用。这个时候,有一位善意的国外用户在 Twitter 上对其余用户进行了揭示。 随后天然是引发了相似最近 fake.js 作者删库、早些时候的 npm left-pad 仓库软件删除雷同的,极其蹩脚的连锁反应,大量软件无奈失常构建。 在一些遗留的我的项目中,咱们能够分明的看到这个事件的产生工夫点,比方 twitter 对 go-bindata 的 fork 存档。 在2月8日,开源社区的其他同学想方法申述失去了这个账号,将“删库”之前的代码复原到了这个账号中,为了表明这个仓库是仅做复原之用处,好心人将软件仓库设置为只读(归档)后,做了一个雷锋式的申明。 在尔后的岁月里,尽管这个仓库失去了原作者的保护。然而 Golang 和 Golang 社区生态仍旧在蓬勃发展,动态资源嵌入的需要还是比拟旺盛的,于是便有了上文中的其余三个开源软件仓库,以及一些我尚未提到的知名度更低的一些仓库。 各个版本的软件的差别下面将各个开源我的项目之间的渊源讲完了,咱们来看看这几个仓库之间都有哪些不同。 在这几个仓库中,go-bindata/go-bindata 是知名度最高的版本,elazarl/go-bindata-assetfs 提供了原版软件不反对 net/http 应用的 FS 封装。还记得上一篇文章中提到的 FS 接口实现吗,没错,这个我的项目次要就是做了这个性能。除此之外,在过来几年里,前端畛域技术的蓬勃发展,尤其是 SPA 类型的前端利用的蓬勃发展,也让 elazarl/go-bindata-assetfs 这个专一于服务 SPA 利用单文件散发的解决方案有了实战的中央。所以如果你有相似的需要,仍旧能够应用这个仓库,将你的前端 SPA 我的项目打包成一个可执行文件进行疾速散发。 当然,开源社区中的软件倒退常常是交织的,在 elazarl/go-bindata-assetfs 提供了 FS 封装不久,go-bindata/go-bindata 也提供了 -fs 参数,反对了将嵌入资源和 net/http 一起应用的性能。所以如果你谋求程序的依赖最小化,并心愿嵌入的资源和 net/http 一起应用,能够思考只应用这个仓库。 ...

January 16, 2022 · 4 min · jiezi

关于golang:动手实现一个localcache-实现篇

原文链接:入手实现一个localcache - 实现篇 前言哈喽,大家好,我是asong,通过了后面两篇的介绍,咱们曾经根本理解该如何设计一个本地缓存了,本文就是这个系列的终结篇,本人入手实现一个本地缓存,接下来且听我细细道来!!! 本文代码曾经上传到github:https://github.com/asong2020/go-localcache 当初这一版本算是一个1.0,后续会持续进行优化和迭代。 第一步:形象接口第一步很重要,以面向接口编程为准则,咱们先形象进去要裸露给用户的办法,给用户提供简略易懂的办法,因而我形象进去的后果如下: // ICache abstract interfacetype ICache interface { // Set value use default expire time. default does not expire. Set(key string, value []byte) error // Get value if find it. if value already expire will delete. Get(key string) ([]byte, error) // SetWithTime set value with expire time SetWithTime(key string, value []byte, expired time.Duration) error // Delete manual removes the key Delete(key string) error // Len computes number of entries in cache Len() int // Capacity returns amount of bytes store in the cache. Capacity() int // Close is used to signal a shutdown of the cache when you are done with it. // This allows the cleaning goroutines to exit and ensures references are not // kept to the cache preventing GC of the entire cache. Close() error // Stats returns cache's statistics Stats() Stats // GetKeyHit returns key hit GetKeyHit(key string) int64}Set(key string, value []byte):应用该办法存储的数据应用默认的过期工夫,如果革除过期的异步工作没有enable,那么就永不过期,否则默认过期工夫为10min。Get(key string) ([]byte, error):依据key获取对象内容,如果数据过期了会在这一步删除。SetWithTime(key string, value []byte, expired time.Duration):存储对象是应用自定义过期工夫Delete(key string) error:依据key删除对应的缓存数据Len() int:获取缓存的对象数量Capacity() int:获取以后缓存的容量Close() error:敞开缓存Stats() Stats:缓存监控数据GetKeyHit(key string) int64:获取key的命中率数据第二步:定义缓存对象第一步咱们形象好了接口,上面就要定义一个缓存对象实例实现接口,先看定义构造: ...

January 15, 2022 · 4 min · jiezi

关于golang:深入浅出-Golang-资源嵌入方案前篇

十分多的语言都具备资源嵌入计划,在 Golang 中,资源嵌入相干的开源计划更是百家争鸣。网络上对于 Golang 资源嵌入的应用计划很多,然而鲜有人分析原理,以及将原生实现和开源实现进行性能比拟,实用场景剖析。 所以本文就来聊聊这个话题,权作抛砖引玉。 写在后面不论是哪一种语言,总会因为一些起因,咱们须要将动态资源嵌入语言编译后果中。Golang 天然也不例外,不过在官网 2019 年 12 月有人提出“资源嵌入性能”草案前,Golang 生态中可能提供这个需要性能的我的项目曾经有不少了,直到 2020 年 Golang 1.16 公布,资源嵌入性能,正式的被官网反对了。 在越来越多的文章、甚至之前实现了资源嵌入性能的开源我的项目纷纷举荐应用官网 go embed 指令来进行性能实现的明天。咱们或者应该更主观的理解“语言原生性能”和三方实现的异同,以及作为谋求性能的 Go 语言生态中技术解决方案性能上的主观差距。 接下来的文章里,我会陆续介绍在 GitHub 成名已久或者被宽泛应用的一些同类我的项目,比方 packr(3.3k stars)、statik (3.4k stars)、go.rice (2.3k stars)、go-bindata (1.5k stars)、vsfgen (1k stars)、esc(0.6k stars)、fileb0x (0.6k stars)... 本篇文章里,咱们先以官网原生性能 go embed 指令为切入点,作为规范参考系,聊聊原理、聊聊根底应用、聊聊性能。 先来聊聊原理。 Go Embed 原理浏览目前最新的 Golang 1.17 的源码,疏忽掉一些和命令行参数解决相干的局部,咱们不难发现和 Embed 无关的次要的代码实现次要在上面四个文件中: src/embed/embed.gosrc/go/build/read.gosrc/cmd/compile/internal/noder/noder.gosrc/cmd/compile/internal/gc/main.goembed/embed.goembed.go 次要提供了 embed 性能在运行时的相干申明和函数定义( FS 的接口实现),以及提供了 go doc 文档中的阐明局部。 FS 接口实现对于想要通过文件系统的形式拜访和操作文件来说十分要害,比方你想应用规范的 FS 函数针对文件进行 “CRUD” 操作。 // lookup returns the named file, or nil if it is not present.func (f FS) lookup(name string) *file { ...}// readDir returns the list of files corresponding to the directory dir.func (f FS) readDir(dir string) []file { ...}func (f FS) Open(name string) (fs.File, error) { ...}// ReadDir reads and returns the entire named directory.func (f FS) ReadDir(name string) ([]fs.DirEntry, error) { ...}// ReadFile reads and returns the content of the named file.func (f FS) ReadFile(name string) ([]byte, error) { ...}通过浏览代码,咱们不难看到在 go embed 中文件被设定为只读,然而如果你违心的话,你齐全能够实现一套可读可写的文件系统,这点咱们前面的文章会提到。 ...

January 15, 2022 · 5 min · jiezi

关于golang:Go-Rust-排序和二分搜索的对比

作者:王东阳 前言 在计算机科学中,排序和二分搜寻是十分常见的一种算法,在上篇文章《leveldb memdb源码剖析(下)之Rust实现篇》中,就能够看到外面很多办法都用到了二分搜寻来实现。本文将会比照 Go 和 Rust 语言中排序和搜寻办法中的一些个性和不同,对于Go次要应用数字切片 []int 作为例子, 对于 Rust 次要应用 Vec 作为例子 。 排序在Go语言中,对于 []int 咱们能够间接应用 sort.Ints 进行排序如下: func sort_simple() { a := []int{1, 2, 6, 7, 8, 3, 4} sort.Ints(a) fmt.Println(a)}在 Rust 中,对于 Vec 能够应用 sort 办法进行排序如下: fn sort_simple() { let mut a = vec![1, 2, 6, 7, 8, 3, 4]; a.sort(); println!("{:?}", a); }如果心愿自定义排序规定,在Go中咱们能够应用 sort.Slice ,实现逆序排序或基于绝对值等特定规定的排序,如下: func sort_reverse() { a := []int{1, 2, 6, 7, 8, 3, 4} sort.Slice(a, func(i, j int) bool { return a[i] > a[j] }) fmt.Println(a)}func sort_abs() { a := []int{1, -2, 6, 7, -8, 3, 4} sort.Slice(a, func(i, j int) bool { return abs(a[i]) > abs(a[j]) }) fmt.Println(a)}func abs(i int) int { if i > 0 { return i } return -i}在Rust中则能够应用 sort_by来自定义排序 ...

January 15, 2022 · 6 min · jiezi

关于golang:Go编译原理系列5抽象语法树构建

前言在上一篇语法分析中,咱们晓得了Go编译器是如何依照Go的文法,解析go文本文件中的各种申明类型(import、var、const、func等)。语法分析阶段将整个源文件解析到一个File的构造体中,源文件中各种申明类型解析到File.DeclList中。最终生成以File构造体为根节点,importDecl、constDecl、typeDecl、varDecl、FuncDecl等为子节点的语法树 首先咱们须要明确的就是,形象语法树的作用其实就是为了后边进行类型查看、代码格调查看等等。总之,有了形象语法树,编译器就能够精准的定位到代码的任何中央,对其进行一些列的操作及验证等 本文为形象语法树的构建,咱们晓得,在编译器前端必须将源程序构建成一种两头示意模式,以便在编译器的后端进行应用,形象语法树就是一种常见的树状的两头示意模式。所以本文次要是介绍Go编译器将语法树构建成形象语法树都做了哪些事件? 形象语法树构建概览以下先从整体上意识形象语法树构建过程,可能跨度比拟大,具体实现细节在下一部分介绍 在上一篇的语法解析阶段咱们晓得,Go编译器会起多个协程,将每一个源文件都解析成一棵语法树。具体代码的地位是:src/cmd/compile/internal/gc/noder.go → parseFiles func parseFiles(filenames []string) uint { noders := make([]*noder, 0, len(filenames)) // Limit the number of simultaneously open files. sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10) for _, filename := range filenames { p := &noder{ basemap: make(map[*syntax.PosBase]*src.PosBase), err: make(chan syntax.Error), } noders = append(noders, p) //起多个协程对源文件进行语法解析 go func(filename string) { sem <- struct{}{} defer func() { <-sem }() defer close(p.err) base := syntax.NewFileBase(filename) f, err := os.Open(filename) if err != nil { p.error(syntax.Error{Msg: err.Error()}) return } defer f.Close() p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error }(filename) } //开始将每一棵语法树构建成形象语法树 var lines uint for _, p := range noders { for e := range p.err { p.yyerrorpos(e.Pos, "%s", e.Msg) } p.node() //构建形象语法树的外围实现 lines += p.file.Lines p.file = nil // release memory ...... } localpkg.Height = myheight return lines}在将源文件解析成一棵语法树之后,Go编译器会将每一棵语法树(源文件)构建成形象语法树。其外围代码就在p.node()这个办法中: ...

January 15, 2022 · 8 min · jiezi

关于golang:golang-经典案例总结

1.反射之用字符串函数名调用函数 package mainimport ( "fmt" "reflect")/**通过反射获取它对应的函数,而后通过call来调用 */func main() { var animal = Animal{} val := reflect.ValueOf(&animal) f := val.MethodByName("Eat") f.Call([]reflect.Value{}) //传参 f3 := val.MethodByName("SetName") params := make([]reflect.Value,1) params[0] = reflect.ValueOf("旺财") f3.Call(params) f2 := val.MethodByName("GetName") f2.Call([]reflect.Value{})}type Animal struct { name string}func (e *Animal) Eat() { fmt.Println("eat test")}func (e *Animal) SetName(name string) { e.name = name}func (e *Animal) GetName() string { fmt.Println("name",e.name) return e.name}

January 14, 2022 · 1 min · jiezi

关于golang:Go-Error-嵌套到底是怎么实现的

原文链接: Go Error 嵌套到底是怎么实现的? Go Error 的设计哲学是 「Errors Are Values」。 这句话应该怎么了解呢?翻译起来挺难的。不过从源码的角度来看,如同更容易了解其背地的含意。 Go Error 源码很简略,寥寥几行: // src/builtin/builtin.gotype error interface { Error() string}error 是一个接口类型,只须要实现 Error() 办法即可。在 Error() 办法中,就能够返回自定义构造体的任意内容。 上面首先说说如何创立 error。 创立 Error创立 error 有两种形式,别离是: errors.New();fmt.Errorf()。errors.New()errors.New() 的应用连续了 Go 的一贯格调,New 一下就能够了。 举一个例子: package mainimport ( "errors" "fmt")func main() { err := errors.New("这是 errors.New() 创立的谬误") fmt.Printf("err 谬误类型:%T,谬误为:%v\n", err, err)}/* 输入err 谬误类型:*errors.errorString,谬误为:这是 errors.New() 创立的谬误*/这段代码惟一让人困惑的中央可能就是谬误类型了,但没关系。只有看一下源码,就霎时迎刃而解。 源码如下: // src/errors/errors.go// New returns an error that formats as the given text.// Each call to New returns a distinct error value even if the text is identical.func New(text string) error { return &errorString{text}}// errorString is a trivial implementation of error.type errorString struct { s string}func (e *errorString) Error() string { return e.s}能够看到,errorString 是一个构造体,实现了 Error() 办法,New 函数间接返回 errorString 指针。 ...

January 14, 2022 · 3 min · jiezi

关于golang:Go-分布式令牌桶限流-兜底策略

上篇文章提到固定工夫窗口限流无奈解决忽然申请洪峰状况,本文讲述的令牌桶线路算法则能够比拟好的解决此场景。 工作原理单位工夫依照肯定速率匀速的生产 token 放入桶内,直到达到桶容量下限。解决申请,每次尝试获取一个或多个令牌,如果拿到则解决申请,失败则拒绝请求。 优缺点长处能够无效解决霎时的突发流量,桶内存量 token 即可作为流量缓冲区平滑解决突发流量。 毛病实现较为简单。 代码实现core/limit/tokenlimit.go 分布式环境下思考应用 redis 作为桶和令牌的存储容器,采纳 lua 脚本实现整个算法流程。 redis lua 脚本-- 每秒生成token数量即token生成速度local rate = tonumber(ARGV[1])-- 桶容量local capacity = tonumber(ARGV[2])-- 以后工夫戳local now = tonumber(ARGV[3])-- 以后申请token数量local requested = tonumber(ARGV[4])-- 须要多少秒能力填满桶local fill_time = capacity/rate-- 向下取整,ttl为填满工夫的2倍local ttl = math.floor(fill_time*2)-- 以后工夫桶容量local last_tokens = tonumber(redis.call("get", KEYS[1]))-- 如果以后桶容量为0,阐明是第一次进入,则默认容量为桶的最大容量if last_tokens == nil thenlast_tokens = capacityend-- 上一次刷新的工夫local last_refreshed = tonumber(redis.call("get", KEYS[2]))-- 第一次进入则设置刷新工夫为0if last_refreshed == nil thenlast_refreshed = 0end-- 间隔上次申请的时间跨度local delta = math.max(0, now-last_refreshed)-- 间隔上次申请的时间跨度,总共能生产token的数量,如果超多最大容量则抛弃多余的tokenlocal filled_tokens = math.min(capacity, last_tokens+(delta*rate))-- 本次申请token数量是否足够local allowed = filled_tokens >= requested-- 桶残余数量local new_tokens = filled_tokens-- 容许本次token申请,计算残余数量if allowed thennew_tokens = filled_tokens - requestedend-- 设置残余token数量redis.call("setex", KEYS[1], ttl, new_tokens)-- 设置刷新工夫redis.call("setex", KEYS[2], ttl, now)return allowed令牌桶限流器定义type TokenLimiter struct { // 每秒生产速率 rate int // 桶容量 burst int // 存储容器 store *redis.Redis // redis key tokenKey string // 桶刷新工夫key timestampKey string // lock rescueLock sync.Mutex // redis衰弱标识 redisAlive uint32 // redis故障时采纳过程内 令牌桶限流器 rescueLimiter *xrate.Limiter // redis监控探测工作标识 monitorStarted bool}func NewTokenLimiter(rate, burst int, store *redis.Redis, key string) *TokenLimiter { tokenKey := fmt.Sprintf(tokenFormat, key) timestampKey := fmt.Sprintf(timestampFormat, key) return &TokenLimiter{ rate: rate, burst: burst, store: store, tokenKey: tokenKey, timestampKey: timestampKey, redisAlive: 1, rescueLimiter: xrate.NewLimiter(xrate.Every(time.Second/time.Duration(rate)), burst), }}获取令牌 ...

January 13, 2022 · 2 min · jiezi

关于golang:Go实战-基于有向无环图的并发执行流的实现

大家好,我是Go学堂的渔夫子。明天跟大家聊聊基于有向无环图的工作流的实现. 01 工作流(workflow)概述工作流,是对工作流程中的工作按肯定的规定组织在一起并按其进行执行的一种模型。比方常见的行政零碎中的加班申请、销假申请;工作流要解决的问题就是为了实现某个特定的指标,让多个参与者之间按某种预订的规定主动的传递信息。 本文介绍了一种基于有向无环图实现的工作流,通过有向无环图,能够解决两个问题:从逻辑上,对各个节点的依赖关系进行了组织;从技术上,有依赖关系的节点须要期待执行,无依赖关系的能够并发执行。 该工作流的理论利用是在程序化广告中从接管申请到广告响应之间的流程:接管申请、获取地理位置、获取用户画像、广告召回、广告排序、算法预估、返回响应等各个节点之间的依赖执行。 但本文的指标是介绍其实现思维,所以在示例局部会以穿衣服的流程为例进行解说。 02 工作流的实现上面咱们以早上起床穿衣所产生的事件为例来解说有向无环图的实现。穿衣流程中蕴含的事件有穿内裤、穿裤子、穿袜子、穿鞋、戴手表、穿衬衣、穿外套等。这些事件中有的必须要先穿某些衣服,能力再穿其余衣服(如先穿袜子后能力穿鞋)。有些事件则能够以任意程序穿上(如袜子和裤子之间能够以任意词序进行穿戴)。如图所示: 由上图能够看到,穿内裤、穿袜子、穿衬衣、戴手表之间没有相互依赖,能够并发执行。而穿鞋子则必须期待所依赖的裤子和袜子穿完后能力执行。上面咱们就来看看如何实现这样的有向无环图的工作流。 2.1 定义工作流构造依据上图,咱们能够看出一个绝对残缺的工作流蕴含开始节点(从哪里开始)、边(通过哪些节点)、完结节点(到哪里完结)。由此,咱们定义工作流的构造如下: type WorkFlow struct { done chan struct{} //完结标识,该标识由完结节点写入 doneOnce *sync.Once //保障并发时只写入一次 alreadyDone bool //有节点出错时终止流程标记 root *Node //开始节点 End *Node //完结节点 edges []*Edge //所有通过的边,边连贯了节点}2.2 定义工作流中边边用来示意两个节点之间的依赖关系。有向图中的边还能表明两个节点哪个是前置节点,哪个是后置节点。后置节点须要期待前置节点的工作执行实现后能力执行。如下图所示: 内裤和裤子两个节点阐明只有等穿上内裤后,能力穿裤子,那么穿内裤节点就是穿裤子节点的前置节点;而鞋子只有等裤子和袜子都穿上后能力穿鞋子,那么裤子和袜子就是鞋子的前置节点。 所以边的示意是从哪个节点到哪个节点。定义如下: type Edge struct { FromNode *Node ToNode *Node}2.3 定义工作流中的节点节点即要具体执行逻辑的工作单元。同时每个节点都有所关联的边。因为咱们应用的是有向图,所以关联的边又分为入边(即终止于该顶点的边)和出边(即从该顶点开始的边)。如下图: 边1是内裤节点的出边,同时也是裤子节点的入边。边2和边3都是鞋子节点的入边。本文将入边称为该节点的依赖边,定义为Dependency,示意只有这些边连贯的节点工作执行完后,该节点能力开始执行。将该节点的出边称为孩子边,定义Children,示意该节点执行完后,能够继续执行的子节点。由此,节点的构造定义如下: type Node struct { Dependency []*Edge //依赖的边 DepCompleted int32 //示意依赖的边有多少个已执行实现,用于判断该节点是否能够执行了 Task Runnable //工作执行 Children []*Edge //节点的字边}在节点的定义中,咱们看到有一个Runnable类型。该类型是一个接口,只有一个Run(i interface{})办法,用来对节点执行业务逻辑的形象。以便在节点执行的时候,对立调用各个节点的Run办法即可。该接口的定义如下: type Runnable interface { Run(i interface{})}咱们以穿鞋子工作为例来实现该接口,定义如下: ...

January 11, 2022 · 2 min · jiezi

关于golang:GORM中文文档

原文连贯: https://blog.csdn.net/u010525... 装置go get -u github.com/jinzhu/gorm import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/sqlite")type Product struct { gorm.Model // gorm.Model 帮咱们定义好了一些字段,如:ID、created_at等等 Code string Price uint}func main() { db, err := gorm.Open("sqlite3", "test.db") if err != nil { panic("failed to connect database") } defer db.Close() //主动查看 Product 构造是否变动,变动则进行迁徙 db.AutoMigrate(&Product{}) // 增 db.Create(&Product{Code: "L1212", Price: 1000}) // 查 var product Product db.First(&product, 1) // 找到id为1的产品 db.First(&product, "code = ?", "L1212") // 找出 code 为 l1212 的产品 // 改 - 更新产品的价格为 2000 db.Model(&product).Update("Price", 2000) // 删 - 删除产品 db.Delete(&product)}模型定义模型个别都是一般的 Golang 的构造体,Go 的根本数据类型,或者指针。sql.Scanner 和 driver.Valuer,同时也反对接口。 ...

January 11, 2022 · 11 min · jiezi

关于golang:Go-中实现用户的每日限额比如一天只能领三次福利

如果你写一个 bug 管理系统,用了这个 PeriodLimit 你就能够限度每个测试人员每天只能给你提一个 bug。工作是不是就轻松很多了?:P现在微服务架构大行其道实质起因是因为要升高零碎的整体复杂度,将零碎危险均摊到子系统从而最大化保证系统的稳定性,通过畛域划分拆成不同的子系统后各个子系统能独立的开发、测试、公布,研发节奏和效率能明显提高。 但同时也带来了问题,比方:调用链路过长,部署架构复杂度晋升,各种中间件须要反对分布式场景。为了确保微服务的失常运行,服务治理就不可或缺了,通常包含:限流,降级,熔断。 其中限流指的是针对接口调用频率进行限度,免得超出承载下限拖垮零碎。比方: 电商秒杀场景API 针对不同商户限流罕用的限流算法有: 固定工夫窗口限流滑动工夫窗口限流漏桶限流令牌桶限流本文次要解说固定工夫窗口限流算法,次要的应用场景比方: 每个手机号每天只能发5条验证码短信每个用户每小时只能间断尝试3次明码每个会员每天只能领3次福利工作原理从某个工夫点开始每次申请过去申请数+1,同时判断以后工夫窗口内申请数是否超过限度,超过限度则回绝该申请,而后下个工夫窗口开始时计数器清零期待申请。 优缺点长处实现简略高效,特地适宜用来限度比方一个用户一天只能发10篇文章、只能发送5次短信验证码、只能尝试登录5次等场景,理论业务中此类场景十分多见。 毛病固定工夫窗口限流的毛病在于无奈解决临界区申请突发场景。 假如每 1s 限流 100 次申请,用户在两头 500ms 时开始 1s 内发动 200 次申请,此时 200 次申请是能够全副通过的。这就和咱们预期 1s 限流 100 次不合了,本源在于限流的细粒度太粗。 go-zero 代码实现core/limit/periodlimit.gogo-zero 中应用 redis 过期工夫来模仿固定工夫窗口。 redis lua 脚本:-- KYES[1]:限流器key-- ARGV[1]:qos,单位工夫内最多申请次数-- ARGV[2]:单位限流窗口工夫-- 申请最大次数,等于p.quotalocal limit = tonumber(ARGV[1])-- 窗口即一个单位限流周期,这里用过期模仿窗口成果,等于p.permitlocal window = tonumber(ARGV[2])-- 申请次数+1,获取申请总数local current = redis.call("INCRBY",KYES[1],1)-- 如果是第一次申请,则设置过期工夫并返回 胜利if current == 1 then redis.call("expire",KYES[1],window) return 1-- 如果以后申请数量小于limit则返回 胜利elseif current < limit then return 1-- 如果以后申请数量==limit则返回 最初一次申请elseif current == limit then return 2-- 申请数量>limit则返回 失败else return 0end固定工夫窗口限流器定义type ( // PeriodOption defines the method to customize a PeriodLimit. // go中常见的option参数模式 // 如果参数十分多,举荐应用此模式来设置参数 PeriodOption func(l *PeriodLimit) // A PeriodLimit is used to limit requests during a period of time. // 固定工夫窗口限流器 PeriodLimit struct { // 窗口大小,单位s period int // 申请下限 quota int // 存储 limitStore *redis.Redis // key前缀 keyPrefix string // 线性限流,开启此选项后能够实现周期性的限流 // 比方quota=5时,quota理论值可能会是5.4.3.2.1呈现出周期性变动 align bool })留神一下 align 参数,align=true 时申请下限将会出现周期性的变动。比方quota=5时理论quota可能是5.4.3.2.1呈现出周期性变动 ...

January 11, 2022 · 2 min · jiezi

关于golang:Lets-Go-Rust-系列之for对比

前言 在golang中提供了for range 语法糖帮忙咱们不便的遍历数据或切片,也能够遍历map和channel;在rust中则提供了 for in 语法糖帮忙咱们不便的遍历Array,Vector或切片,也能够遍历map。本文将会通过多种类型的例子介绍两种语言中这些语法糖背地的机制以及使用不当可能遇到的陷阱。 遍历形式比照 Golang 咱们先来看Golang中的三种遍历形式: arr := []int{2, 4, 6} // 只有索引 for i := range arr { fmt.Println(i) } // 索引和数值 for i, v := range arr { fmt.Println(i, v) } // 只有数值 for _, v := range arr { fmt.Println(v) }输入0120 21 42 6246 Rust 首先咱们要理解在rust中遍历arr有上面四种不同的办法,实质都是将以后arr转为了相应的iterator。 let arr = vec![1, 2, 3]; for a in arr { println!("{}", a); } let arr = vec![1, 2, 3]; for a in arr.into_iter() { println!("{}", a); } let arr = vec![1, 2, 3]; for a in arr.iter() { println!("{}", a); } let mut arr = vec![1, 2, 3]; for a in arr.iter_mut() { println!("{}", a); }其中 for a in arr 等价于for a in arr.into_iter() ,这种遍历形式会把以后arr中的变量 move 掉,执行遍历后,arr无奈再应用。 ...

January 11, 2022 · 6 min · jiezi

关于golang:Golang定时器的终止与重置

作者:ReganYue 起源:恒生LIGHT云社区 Golang:定时器的终止与重置大家好,这里是致力变得优良的R君,这次咱们持续来进行Golang系列《让咱们一起Golang》,昨日有读者对定时器的终止有疑难,本次咱们来理解Golang的定时器的终止与重置这也是一个比拟容易了解的知识点,一起来看一看吧! 先看上面一段代码: func main() { timer := time.NewTimer(3 * time.Second) fmt.Println(time.Now(),"炸弹将于3秒后引爆") timer.Stop() fmt.Println("定时炸弹已拆除,定时器生效") t := <-timer.C fmt.Println("炸弹引爆于",t)}先来看看运行后果 2021-08-25 10:08:34.706412 +0800 CST m=+0.023017601 炸弹将于3秒后引爆定时炸弹已拆除,定时器生效fatal error: all goroutines are asleep - deadlock!咱们能够趁定时器工夫未到而应用Stop来将定时器终止,如果定时器已被叫停,其工夫管道永远读不出数据了,如果强制读取,就会呈现死锁。因为应用Stop就是进行往管道外面写数据了,或者能够这样说,就是管道外面的数据曾经读完了,应用 time.NewTimer(3 * time.Second)就是往管道外面写数据。 咱们在来看一个乏味的例子。 func main() { timer := time.NewTimer(1 * time.Second) fmt.Println(time.Now()) time.Sleep(2 * time.Second) fmt.Println(time.Now()) timer.Reset(10*time.Second) fmt.Println("炸弹引爆于",<-timer.C)}当初,思考一下,炸弹是什么时候引爆的! 想晓得答案吗?不要焦急,不要焦急,劳动,劳动一会儿,答案马上揭晓 咱们来看看运行后果吧: 2021-08-25 10:15:16.8406335 +0800 CST m=+0.0149998012021-08-25 10:15:18.906213 +0800 CST m=+2.080579301炸弹引爆于 2021-08-25 10:15:17.8522233 +0800 CST m=+1.026589601是不是和你想的一样?如果不是,没关系,听我细细道来。 因为time.sleep()是让主协程睡大觉,而timer.C读的那条管道的协程是独立的。所以你让主协程睡大觉并不会影响定时器的计时,就相当于一个定时炸弹要引爆了,你马上把手表的工夫往后调,然而定时炸弹上的数字工夫不会因为手表上的工夫往后调而往后调。 诶!这时你会说我不是重置了吗? ...

January 11, 2022 · 1 min · jiezi

关于golang:golang性能分析利器pprof

前言作为一名gopher,不晓得你是否遇到过以下问题? CPU忽然飙高(甚至死循环,CPU跑满)?某个性能接口QPS在压测中始终压不下来?利用呈现goroutine泄露?内存居高不下?在某处加锁的逻辑中,迟迟得不到锁?你是否能得心应手的找到问题的症结所在,你又是应用什么办法或工具解决的呢?明天我将介绍下我常常应用的工具pprof.它是golang自带的性能剖析大杀器,基本上能疾速解决上述问题。 如何应用pprof应用pprof有三种姿态,一种是应用runtime/pprof/pprof.go另一种是应用net/http/pprof/pprof.go(底层也是应用runtime/pprof),还有一种是在单元测试中生成profile 数据。具体的办法在对应的pprof.go文件结尾有阐明。 1. runtime/pprof 形式pprofpackage mainimport ( "flag" "log" "os" "runtime" "runtime/pprof")var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")var memprofile = flag.String("memprofile", "", "write memory profile to `file`")func main() { flag.Parse() if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal("could not create CPU profile: ", err) } defer f.Close() // error handling omitted for example if err := pprof.StartCPUProfile(f); err != nil { log.Fatal("could not start CPU profile: ", err) } defer pprof.StopCPUProfile() } // ... rest of the program ... if *memprofile != "" { f, err := os.Create(*memprofile) if err != nil { log.Fatal("could not create memory profile: ", err) } defer f.Close() // error handling omitted for example runtime.GC() // get up-to-date statistics if err := pprof.WriteHeapProfile(f); err != nil { log.Fatal("could not write memory profile: ", err) } }}这种形式须要你手动启动须要pprof的类型,比方,开启CPU profile 还是heap profile 等等,pprof 会在利用启动到完结的整个生命周期生成profile 文件。其实生成profile 数据是会损耗性能的,生产环境不倡议始终开启,能够在须要剖析的时候长期采集那个时刻的数据,如通过监听系统信号的形式开启/敞开pprof,示例代码如下: ...

January 10, 2022 · 3 min · jiezi

关于golang:GoLangGO命令中go-get拉取库卡住慢的解决方法

GO命令中go get拉取库卡住、慢的解决办法老手,像我在学习go的时候发现应用go get去拉取依赖库的时候会很慢,有些甚至是基本拉取不到,网上有很多解决方案,设置代理,应用gopm。 gopm是相似于node.js的包管理工具,具体网上也有很多材料介绍;贴个链接:) [gopm介绍](https://www.jianshu.com/p/db9e6ae0d227) 然而gopm又要用go get去拉取,这不是~~套娃~~ 吗; 所以,还是一了百了,设置代理就好了; 如果你是go1.13以上,你就这样:Windows用cmd、powershell,Linux or Mac用Terminal执行下列: go env -w GO111MODULE=ongo env -w GOPROXY=https://goproxy.io,direct# 设置不走 proxy 的公有仓库,多个用逗号相隔(可选)go env -w GOPRIVATE=*.corp.example.com# 设置不走 proxy 的公有组织(可选)go env -w GOPRIVATE=example.com/org_name如果你的go是1.13以下呢,倡议:Windows: # 启用 Go Modules 性能$env:GO111MODULE="on"# 配置 GOPROXY 环境变量$env:GOPROXY="https://goproxy.io"Linux or Mac: # 启用 Go Modules 性能export GO111MODULE=on# 配置 GOPROXY 环境变量export GOPROXY=https://goproxy.io倡议放到.profile或.bash_profile环境变量文件中;这样你的go get就很快了; 我是个搞Java的Golang菜鸟,一起学习成长;

January 10, 2022 · 1 min · jiezi

关于golang:Golang-数组和切片

一、数组 与其余大多数语言相似,Go语言的数组也是一个元素类型雷同的定长的序列。 (1)数组的创立。 数组有3种创立形式:[length]Type 、[N]Type{value1, value2, ... , valueN}、[...]Type{value1, value2, ... , valueN} 如下: func test5() { var iarray1 [5]int32 var iarray2 [5]int32 = [5]int32{1, 2, 3, 4, 5} iarray3 := [5]int32{1, 2, 3, 4, 5} iarray4 := [5]int32{6, 7, 8, 9, 10} iarray5 := [...]int32{11, 12, 13, 14, 15} iarray6 := [4][4]int32{{1}, {1, 2}, {1, 2, 3}} fmt.Println(iarray1) fmt.Println(iarray2) fmt.Println(iarray3) fmt.Println(iarray4) fmt.Println(iarray5) fmt.Println(iarray6)}后果: [0 0 0 0 0][1 2 3 4 5][1 2 3 4 5][6 7 8 9 10][11 12 13 14 15][[1 0 0 0] [1 2 0 0] [1 2 3 0] [0 0 0 0]]咱们看数组 iarray1,只申明,并未赋值,Go语言帮咱们主动赋值为0。再看 iarray2 和 iarray3 ,咱们能够看到,Go语言的申明,能够表明类型,也能够不表明类型,var iarray3 = [5]int32{1, 2, 3, 4, 5} 也是齐全没问题的。 ...

January 10, 2022 · 3 min · jiezi

关于golang:Go-JSON编码与解码

Go JSON编码与解码?JSON简介1. 什么是JSON?JSON全称为Javascript Object Notation,一种数据结构化交互的标准协议,易于浏览与编写,所以在数据交互时宽泛应用。 2. JSON中的数据类型数字:有十进制和迷信记数学两种示意形式。字符串:应用双引号示意的Unicode字符序列。布尔:true或者false。对象:花括号({})括起来的一个或多个键值对(key/value),用逗号(,)隔开,最初一个键值对前面不能有逗号,键必是双引号("")引起来的字符串,而值则可是作意类型(布尔、数字、对象、数组、字符串)。数组:中括号([])括号值的汇合,这些值可是任意类型(布尔、数字、对象、数组、字符串)。上面的示例,是一个数组中包含两个对象。[{"id":1,"username":"xiaoming","gender":1,"email":"xiaoming@163.com"},{"id":2,"username":"xiaohong","gender":2,"email":"xiaohong@163.com"}]JSON与GO联合应用encoding/json解决JSON编码与解码时,就必须解决好JSON数据类型与Go语言数据类型的对应关系。 JSON的数字、字符串、布尔等在Go语言中相应内置数据类型一一对应。JSON的数组则对应Go的数组或Slice(切片)。JSON的对象则对应Go的struct(构造体)或map。编码一个构造体时,构造体中只有首字母大写的成员才会被编码,首字母小写的成员会被疏忽,另外,构造体中字段前面容许应用反引号申明成员的Tag,用于阐明成员的元信息。type Member struct { Id int `json:"id"` Username string `json:"username"` Sex uint `json:"gender"` Email string `json:"email"`}下面的构造体Member中,咱们定义了四个成员,并申明了每个成员的Tag信息, 其中Sex的Tag信息申明为gender,所以编码后的后果为:[{"id":1,"username":"xiaoming","gender":1,"email":"xiaoming@163.com"},{"id":2,"username":"xiaohong","gender":2,"email":"xiaohong@163.com"}]编码将Go语言的数据序列化为JSON字符串的操作,称为编码;编码后的后果为一个JSON格局的字符串。 1. json.Marshal函数应用json.Marshal函数能够间接编码任意数据类型。import ( "encoding/json" "fmt")func main() {members := []Member{ { Id:1, Username:"小明", Sex:1, Email:"xiaoming@163.com", }, { Id:2, Username:"小红", Sex:1, Email:"xiaohong@163.com", }, { Id:3, Username:"小华", Sex:2, Email:"xiaohua@163.com", },} data,_ := json.Marshal(members) fmt.Printf("%s",data)}运行后果: [{"id":1,"username":"小明","gender":1,"email":"xiaoming@163.com"},{"id":2,"username":"小红","gender":1,"email":"xiaohong@163.com"},{"id":3,"username":"小华","gender":2,"email":"xiaohua@163.com"}]json.Encoderjson.Marshal实际上只是对json.Encoder的封装,因而应用json.Encoder同样能够编码JSON。 案例1 func main(){ b := &bytes.Buffer{} encoder := json.NewEncoder(b) err := encoder.Encode(members) if err != nil{ panic(err) } fmt.Println(b.String())}案例 2 ...

January 10, 2022 · 2 min · jiezi

关于golang:golang-map基础知识

map初始化的四种办法 var myGreeting map[string]string fmt.Println(myGreeting) // map[] fmt.Println(myGreeting == nil) //true myGreeting2 := make(map[string]string) myGreeting2["Tim"] = "Good morning." myGreeting2["Jenny"] = "Bonjour." fmt.Println(myGreeting2) //map[Jenny:Bonjour. Tim:Good morning.] myGreeting3 := map[string]string{} myGreeting3["Tim"] = "Good morning." myGreeting3["Jenny"] = "Bonjour." fmt.Println(myGreeting3) //map[Jenny:Bonjour. Tim:Good morning.] myGreeting4 := map[string]string{ "Time": "Good morning.", "Jenny": "Bonjour.", } fmt.Println(myGreeting4) //map[Jenny:Bonjour. Time:Good morning.] fmt.Println(myGreeting4["Jenny"]) //Bonjour.map增加操作 myGreeting := map[string]string{ "Tim": "Good morning!", "Jenny": "Bonjour!", } myGreeting["Harleen"] = "Howdy" fmt.Println(myGreeting)len 获取map的长度 myGreeting := map[string]string{ "Tim": "Good morning!", "Jenny": "Bonjour!", } myGreeting["Harleen"] = "Howdy" fmt.Println(len(myGreeting))更新map myGreeting := map[string]string{ "Tim": "Good morning!", "Jenny": "Bonjour!", } myGreeting["Harleen"] = "Howdy" fmt.Println(myGreeting) myGreeting["Harleen"] = "Gidday" fmt.Println(myGreeting)删除map的值: myGreeting := map[string]string{ "zero": "Good morning!", "one": "Bonjour!", "two": "Buenos dias!", "three": "Bongiorno!", } fmt.Println(myGreeting) delete(myGreeting, "two") fmt.Println(myGreeting) // ------------------------------------------------------------ myGreeting := map[int]string{ 0: "Good morning!", 1: "Bonjour!", 2: "Buenos dias!", 3: "Bongiorno!", } fmt.Println(myGreeting) delete(myGreeting, 7) fmt.Println(myGreeting)判断key是否存在 myGreeting := map[int]string{ 0: "Good morning!", 1: "Bonjour!", 2: "Buenos dias!", 3: "Bongiorno!", } fmt.Println(myGreeting) // delete(myGreeting, 2) if val, exists := myGreeting[2]; exists { fmt.Println("That value exists.") fmt.Println("val: ", val) fmt.Println("exists: ", exists) } else { fmt.Println("That value doesn't exist.") fmt.Println("val: ", val) fmt.Println("exists: ", exists) } fmt.Println(myGreeting)scoreMap := make(map[string]int) scoreMap["张三"] = 90 scoreMap["小明"] = 100 // 如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值 v, ok := scoreMap["张三"] if ok { fmt.Println(v) } else { fmt.Println("查无此人") }map的遍历 myGreeting := map[int]string{ 0: "Good morning!", 1: "Bonjour!", 2: "Buenos dias!", 3: "Bongiorno!", } for key, val := range myGreeting { fmt.Println(key, " - ", val) }} scoreMap := make(map[string]int) scoreMap["张三"] = 90 scoreMap["小明"] = 100 scoreMap["王五"] = 60 for k := range scoreMap { fmt.Println(k) }

January 10, 2022 · 2 min · jiezi

关于golang:终于解决了这个线上偶现的panic问题

来自公众号:Gopher指北不晓得其他人是不是这样,反正老许最怕听到的词就是“偶现”,至于起因我不多说,懂的都懂。 上面间接看panic信息。 runtime error: invalid memory address or nil pointer dereferencepanic(0xbd1c80, 0x1271710) /root/.go/src/runtime/panic.go:969 +0x175github.com/json-iterator/go.(*Stream).WriteStringWithHTMLEscaped(0xc00b0c6000, 0x0, 0x24) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/stream_str.go:227 +0x7bgithub.com/json-iterator/go.(*htmlEscapedStringEncoder).Encode(0x12b9250, 0xc0096c4c00, 0xc00b0c6000) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/config.go:263 +0x45github.com/json-iterator/go.(*structFieldEncoder).Encode(0xc002e9c8d0, 0xc0096c4c00, 0xc00b0c6000) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/reflect_struct_encoder.go:110 +0x78github.com/json-iterator/go.(*structEncoder).Encode(0xc002e9c9c0, 0xc0096c4c00, 0xc00b0c6000) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/reflect_struct_encoder.go:158 +0x3f4github.com/json-iterator/go.(*structFieldEncoder).Encode(0xc002eac990, 0xc0096c4c00, 0xc00b0c6000) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/reflect_struct_encoder.go:110 +0x78github.com/json-iterator/go.(*structEncoder).Encode(0xc002eacba0, 0xc0096c4c00, 0xc00b0c6000) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/reflect_struct_encoder.go:158 +0x3f4github.com/json-iterator/go.(*OptionalEncoder).Encode(0xc002e9f570, 0xc006b18b38, 0xc00b0c6000) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/reflect_optional.go:70 +0xf4github.com/json-iterator/go.(*onePtrEncoder).Encode(0xc002e9f580, 0xc0096c4c00, 0xc00b0c6000) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/reflect.go:219 +0x68github.com/json-iterator/go.(*Stream).WriteVal(0xc00b0c6000, 0xb78d60, 0xc0096c4c00) /go/pkg/mod/github.com/json-iterator/go@v1.1.11/reflect.go:98 +0x150github.com/json-iterator/go.(*frozenConfig).Marshal(0xc00012c640, 0xb78d60, 0xc0096c4c00, 0x0, 0x0, 0x0, 0x0, 0x0)首先我深信一条,开源的力量值得信赖。因而老许第一波操作就是,剖析业务代码是否有逻辑破绽。很显著,共事也是值得信赖的,因而果决猜想是某些未曾构想到的数据触发了边界条件。接下来就是保留现场的惯例操作。 如题目所说,这是偶现的panic问题,因而依照下面的分类采纳合乎以后技术栈的办法保留现场即可。接下来就是坐等播种的节令,而这一等就是好多天。两头数次收到告警,却没有合乎预期的现场。 这个时候我不仅不慌,甚至还有点小冲动。某某曾曰:“要敢于质疑,敢于挑战权威”,一念至此便一发不可收拾,我老许又要为开源事业做出奉献了嘛!说干就敢干,怀着小心理开始浏览json-iterator的源码。 刚开始研读我便明确了一个情理, “当上帝关了这扇门,肯定会为你关上另一扇门”这句话是骗人的。老许只感觉上帝不仅关上了所有的门甚至还关上了所有的窗。上面咱们看看他到底是怎么关门的。 func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { stream := cfg.BorrowStream(nil) defer cfg.ReturnStream(stream) stream.WriteVal(v) if stream.Error != nil { return nil, stream.Error } result := stream.Buffer() copied := make([]byte, len(result)) copy(copied, result) return copied, nil}// WriteVal copy the go interface into underlying JSON, same as json.Marshalfunc (stream *Stream) WriteVal(val interface{}) { if nil == val { stream.WriteNil() return } // 省略其余代码}依据panic栈晓得是因为空指针造成了panic,而(*frozenConfig).Marshal函数外部曾经做了非空判断。到此,老许真的曾经别无他法只得战略性放弃解决此次panic。毕竟,这个影响也没那么大,而且程序员哪有修的完的bug呢。通过这样一番刺激,心里的确容易接受多了。 ...

January 9, 2022 · 1 min · jiezi

关于golang:Go-如何编写-ProtoBuf-插件-三

前言上篇文章《Go - 如何编写 ProtoBuf 插件 (二) 》,分享了基于 自定义选项 定义了 interceptor 插件,而后在 helloworld.proto 中应用了插件,最初在 golang 代码中获取到应用的插件信息。 接上篇,持续分享。 既然获取到了插件信息,咱们就能够应用它们。本文次要分享在 grpc.ServerOption 中的 grpc.UnaryInterceptor 中应用。 演示代码还是以上篇文章中 helloworld.proto 为例。 // 生成 helloworld.pb.go// 生成 helloworld_grpc.pb.go// 应用的 protoc --version 为 libprotoc 3.18.1// 应用的 protoc-gen-go --version 为 protoc-gen-go v1.27.1// 应用的 protoc-gen-go-grpc --version 为 protoc-gen-go-grpc 1.1.0// 在根目录下执行 protoc 命令protoc --go_out=helloworld/gen --go-grpc_out=helloworld/gen helloworld/helloworld.proto一、基于上篇文章中获取 options 的代码进行批改,次要是将其存入到构造体即可。 // 演示代码,构造体var handlers = &struct { Methods map[string]*options.MethodHandler // FullMethod : Handler Services map[string]*options.ServiceHandler // FullMethod : Handler}{ Methods: make(map[string]*options.MethodHandler), Services: make(map[string]*options.ServiceHandler),}二、在 grpc.NewServer 中应用拦截器。 ...

January 9, 2022 · 1 min · jiezi

关于golang:Gin学习笔记01-框架使用

Go Webnet/http库package mainimport ( "fmt" "net/http")func sayHello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello")}func main() { http.HandleFunc("/hello", sayHello) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println("http server failed, err:", err) }}开启服务 go run main.go拜访浏览器 http://localhost:9090/hellohttp/template库模板文件 hello.tmpl <!DOCTYPE html><html lang="en"><head> <title>Hello</title></head><body> <p>{{ . }}</p></body></html>main.go func sayHello(w http.ResponseWriter, r *http.Request) { //解析模板 t, _ := template.ParseFiles("./hello.tmpl") //渲染模板 t.Execute(w, "World")}func main() { http.HandleFunc("/", sayHello) http.ListenAndServe(":9091", nil)}参数渲染t.Execute(w, map[string]interface{}{ "a": "aaa",//{{ .a }} "b": "bbb",//{{ .b }}})模板正文{{/* .a */}}条件判断{{ if lt .a 1}}a < 1{{ else }}a >= 1{{ end }} 循环t.Execute(w, map[string]interface{}{ "num": []string{"a", "b", "c"},}){{ range $k,$v := .num}}<p>{{ $k }} - {{ $v }}</p>{{ else }}---{{ end }} 继承t, err := template.ParseFiles("./base.tmpl","./index.tmpl")name := "AAA"t.ExecuteTemplate(w, "index.tmpl", name)base.tmpl ...

January 9, 2022 · 6 min · jiezi

关于golang:Go编译原理系列4语法分析

前言在上一篇文章中,分享了Go编译器是如何将源文件解析成Token的。本文次要是分享,语法分析阶段是如何依据不同的Token来进行语法解析的。本文你能够理解到以下内容: Go语法分析整体概览Go语法解析具体过程示例展现语法解析残缺过程 Tips:文中会波及到文法、产生式相干内容,如果你不太理解,请先看一下前边的词法剖析&语法分析根底这篇文章 文章比拟长,但代码比拟多,次要是不便了解。置信看完肯定有所播种 Go语法分析整体概览为了不便后边的了解,我这里提供一个源文件,后边的内容,你都能够依照这个源文件中的内容,带入去了解: package mainimport ( "fmt" "go/token")type aType stringconst A = 666var B = 888func main() { fmt.Println("Test Parser") token.NewFileSet()}入口在上一篇文章介绍词法剖析的时候,具体的阐明了Go的编译入口,在编译入口处初始化了语法分析器,并且在初始化语法分析器的过程中初始化了词法分析器,所以词法分析器是内嵌在了语法分词器的外部的,咱们能够在:src/cmd/compile/internal/syntax/parser.go中看到语法分析器的构造如下: type parser struct { file *PosBase //记录关上的文件的信息的(比方文件名、行、列信息) errh ErrorHandler //报错回调 mode Mode //语法分析模式 pragh PragmaHandler scanner //词法分析器 base *PosBase // current position base first error // first error encountered errcnt int // number of errors encountered pragma Pragma // pragmas fnest int // function nesting level (for error handling) 函数的嵌套层级 xnest int // expression nesting level (for complit ambiguity resolution) 表达式嵌套级别 indent []byte // tracing support(跟踪反对)}因为在上一篇文章中曾经具体的分享了入口文件的地位及它都做了什么(src/cmd/compile/internal/syntax/syntax.go → Parse(...)),在语法分析器和词法分析器初始化实现后,咱们会看到它调用了语法分析器的fileOrNil()办法,它就是语法分析的外围办法,下边就具体介绍一下这个外围办法具体做了哪些事件 ...

January 8, 2022 · 8 min · jiezi

关于golang:超全面的Golang实践经验分享

云联壹云是齐全自研的一套交融云平台,Golang是次要的开发语言,本文次要介绍介绍在迭代过程中对于Golang的教训以及在Golang上积攒的框架和库。 在开发过程中,咱们也积攒了Golang的库函数,并基于这些库函数去开发框架以及平台,当然还有库的特点,实现库的起因及其长处。  背景介绍 交融云平台—云联壹云是从2017年开始逐渐迭代开发,平台在17年时是公有云,可能治理在用户部署在本地物理机上的KVM,同时也能治理裸金属的服务器。 过后企业的IT环境并不仅仅是本地的虚拟机以及裸金属,企业的IT基础设施曾经逐渐驳回多云的技术。 所以平台不仅能治理本地IT环境中的虚拟机和裸金属。还能治理其余云,特地是可能帮忙企业治理私有云的资源, 做到所有的资源在一个平台上对立纳管,运维,操作,起到升高运维复杂度并进步企业IT运维效率的目标。 平台后端采纳的是Golang,目前为止已有60万行代码,前端采纳的是Vue框架,整个平台是基于微服务的框架,每个服务之间的认证鉴权是基于Keystone组件。 Golang积攒 首先是Golang的服务框架,所有的组件都是基于这个服务框架来开发,服务框架的特点比拟适宜在咱们平台开发,并且针对平台的特点做出优化,适宜疾速开发服务。 Golang框架 根本所有服务都是基于这个服务框架开发,此框架是比拟不便做CRUD的脚手架框架。 因为服务次要是对云资源的操作,比方云资源的创立、删除、更新等。 因为云的资源十分多,通过脚手架可能比拟不便地实现资源的CRUD操作,再加上其余机制实现对云资源的简单操作以及信息回复。 除CRUD脚手架外,其实它把平台的特地性能加进去,首先组件之间是基于keystone认证,所以在将keystone认证加到框架中,则开发不需关注keystone认证,只有代码是在框架中实现的,天生就集成了keystone认证。 每一个API都受到权限的管制,权限管制也集成到框架中,每一个开发者在开发平台相应的restapi时,不用为权限写相应的代码,可能人造地将权限管制集成到API中。 微服务框架的每一个服务都有相应的配置,如何不便地治理服务配置,并进行更新 ,同步到相应的组件使其失效,此过程绝对简单,咱们将服务配置的性能集成到框架中,开发者采纳框架不用思考配置的存储、更新、服务器读取更新并使配置失效,这些简单事宜已在框架中解决。 还有异步工作的治理性能,平台能够被认为是一个分布式的零碎,云控制器须要去操作和治理数据计算节点、裸金属的治理节点。协调组件之间的简单操作,例如将虚拟机、裸金属创立起来,这些都是分布式的工作治理,在平台中也嵌入了异步工作治理框架。如此即可较为不便地实现异步工作。 CRUD脚手架原理 在平台中,每一种资源,例如主机,在底层对应到数据库MySQL表,资源的状态、相应的属性都记录到了MySQL表中。 用户通过调用API对数据进行操作,在数据操作的同时也能做额定的异步的task,而后去实现相应性能。落到底层代码中就是一种资源对应到一张MySQL表。 为了去比拟不便地实现对数据库MySQL记录的操作,针对每一个资源,都会对应到ModelManager和Model的一对数据结构。 ModelManager数据结构是对应到Golang的structs,这个构造能够实现这一类资源的汇合操作,例如创立资源或者列表,而针对单个资源的操作,则通过Model来实现,实现对某个资源的更新、删除的操作。 Model对应到Golang的构造体,构造体有若干字段,每个字段代表资源的属性,例如此处有一个用户的资源 ,用户的id、Extra属性,用户是否enabled ,用户何时创立,归属的域,都是这个用户资源相应的属性。 这个属性就是Golang构造体的字段,通过构造体字段的Tag属性,如此即可定义每个字段在MySQL的数据库中对应的schema的定义。 例如Id这个字段,属性中有width:"64" charset:"ascii" nullable:"false" primary:"true" 这定义了在Id这个字段是数据库外面的一个varchar(64)的字段,并且他的字符集是ascii码。所以通过tag将构造体的字段映射到了MySQL的schema的字段中,如此,每一个model通过字段的定义就可能清晰地映射到MySQL的数据表中。 这样咱们就实现了Model的字段和MySQL的数据表定义的严格同步,每次程序启动时都会查看,如果Model 的定义和数据表的定义不太统一,而后就会执行相应的SQL的变更操作,将表的定义和Model的定义变更为统一。 例如咱们将Id的宽度从64改成80,在程序重启时就可能发现这个变动,而后将数据表的宽度也变更成80。 如此即可实现通过代码定义的Model 和数据库中的表准确地映射上。 每个 Model、资源都会提供一系列的API,此处曾经列出对一个资源会实现的九类API。 例如创立、删除、更新、执行操作、获取详情、列表等操作。 每一个操作对应restapi,每一个restapi 对应到后端代码中就对应到了每一个资源对应的Manager或者Model的办法。 例如咱们要获取资源详情的办法就是他restapi门路就是GETresources,resources 的Id,调用这个restapi 就映射到相应的Model的GetDetails的办法。 为了实现获取资源的详情只须要去实现Model中的GetDetails的办法的内容,如此即可实现restapi的性能。 通过框架简化了实现restapi的流程,只须要把相应的Model和ModelManager的办法依据输出实现相应逻辑,而后把正确的输入返回回去,这个restapi的性能即可实现。 如此诸如健全 、认证、配置、同步等周边的工作即可在框架中实现,从而大大晋升开发效率并升高在开发过程中犯错的几率。 框架中蕴含许多内容,包含认证、权限、配置变更治理 、配额治理等。 Golang 库 上面介绍在过来开发过程中积攒的Golang库。有利于更加不便 、高效地实现须要的性能。 jsonutils是一个JSON序列化和反序列的工具库。 Golang 的规范库中带的库是encoding/json,encoding/json也是一个十分弱小、十分高效的序列化和反序列的工具库,上面为大家介绍为何抛开encoding/json另外实现jsonutils的库。 encoding/json实现的是Golang的数据结构和对应json的字符串之间的互相转换。 咱们能够把Golang中的构造体通过Marshal的形式生成一个Json的字符串,或者把Json的字符串通过Unmarshal放到相应的构造体中的各个字段,这样即可拜访构造体去取得json中的这些值。 jsonutils与encoding/json相比的显著区别是两头减少了一个两头态,在jsonutils库外面实现JSONObject。 这是两头态的无类型的数据,咱们能够把数据结构Marshal(s)成JSONObject,JSONObject是Golang的interface。 上层是一个构造体,interface能够进一步地序列化成json字符串。 ...

January 7, 2022 · 1 min · jiezi

关于golang:Golang-汇编介绍

在浏览 Golang 源代码时,总是被其中的汇编代码卡住,读起来不晦涩。明天来简要理解下 Golang 中的汇编语言。汇编分类按指令集架构分类(针对 CPU)x86汇编(32bit):这种架构常被称为i386, x86x86汇编(64bit), 这种架构常被称为 AMD64, Intel64, x86-64, x64, 它是 AMD 设计的, 是 x86 架构的 64 位扩大, 起初公开ARM汇编, ARM处理器因为高性能, 低耗电, 罕用于嵌入式, 挪动设施....按汇编格局分类(针对人的浏览习惯)Intel 格局AT&T 格局平时咱们说 golang 中汇编属于 plan9 格调,是按第二种形式分类的,其浏览格调(符号)与 Intel 与 AT&T 都有不同。plan9 汇编作者是 unix 操作系统的同一批人,bell 实验室所开发的。 Go汇编语言是基于 plan9 汇编,然而事实世界还有这么多不同架构的 CPU 在这。所以 golang 汇编在 plan9 格调下,同一个办法还有不同指令集架构的多种实现。 在哪能看到 Golang 汇编代码Golang 源代码中,如src/runtime/asm_amd64.s ,src/math/big/ ...go tool compile -S main.go,把本人编写的代码编译成汇编代码。如:在我的 Mac Intel 机器上,amd64的架构,汇编代码生成如下:$ cat main.go package mainfunc main() { a, b := 0, 0 println(a + b)}$ go tool compile -S main.go "".main STEXT size=66 args=0x0 locals=0x10 funcid=0x0 0x0000 00000 (main.go:3) TEXT "".main(SB), ABIInternal, $16-0 0x0000 00000 (main.go:3) CMPQ SP, 16(R14) 0x0004 00004 (main.go:3) PCDATA $0, $-2 0x0004 00004 (main.go:3) JLS 57 0x0006 00006 (main.go:3) PCDATA $0, $-1 0x0006 00006 (main.go:3) SUBQ $16, SP 0x000a 00010 (main.go:3) MOVQ BP, 8(SP) 0x000f 00015 (main.go:3) LEAQ 8(SP), BP 0x0014 00020 (main.go:3) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0014 00020 (main.go:3) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0014 00020 (main.go:5) PCDATA $1, $0 0x0014 00020 (main.go:5) CALL runtime.printlock(SB) 0x0019 00025 (main.go:5) XORL AX, AX...Go 汇编根底语法1. 寄存器通用寄存器寄存器与物理机架构相干, 不同的架构有不同的物理寄存器。 ...

January 7, 2022 · 3 min · jiezi

关于golang:为什么要避免在-Go-中使用-ioutilReadAll

原文链接: 为什么要防止在 Go 中应用 ioutil.ReadAll? ioutil.ReadAll 次要的作用是从一个 io.Reader 中读取所有数据,直到结尾。 在 GitHub 上搜寻 ioutil.ReadAll,类型抉择 Code,语言选择 Go,一共失去了 637307 条后果。 这阐明 ioutil.ReadAll 还是挺受欢迎的,次要也是用起来的确不便。 然而当遇到大文件时,这个函数就会暴露出两个显著的毛病: 性能问题,文件越大,性能越差。文件过大的话,可能间接撑爆内存,导致程序解体。为什么会这样呢?这篇文章就通过源码来剖析背地的起因,并试图给出更好的解决方案。 上面咱们正式开始。 ioutil.ReadAll首先,咱们通过一个例子看一下 ioutil.ReadAll 的应用场景。比如说,应用 http.Client 发送 GET 申请,而后再读取返回内容: func main() { res, err := http.Get("http://www.google.com/robots.txt") if err != nil { log.Fatal(err) } robots, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) } fmt.Printf("%s", robots)}http.Get() 返回的数据,存储在 res.Body 中,通过 ioutil.ReadAll 将其读取进去。 外表上看这段代码没有什么问题,但仔细分析却并非如此。想要探索其背地的起因,就只能靠源码谈话。 ioutil.ReadAll 的源码如下: // src/io/ioutil/ioutil.gofunc ReadAll(r io.Reader) ([]byte, error) { return io.ReadAll(r)}Go 1.16 版本开始,间接调用 io.ReadAll() 函数,上面再看看 io.ReadAll() 的实现: ...

January 6, 2022 · 4 min · jiezi

关于golang:Docker入门教程101-基于Docker部署Go项目

环境筹备Docker装置:参考我的上一篇文章Docker入门教程101:用处,架构,装置和应用。Go我的项目代码筹备 基于golang最风行的Web框架Gin,搭建一个最简略的Web服务,大家能够下载zip包,或者应用git下载源码: $ git clone git@github.com:jincheng9/disributed-system-notes.git 下载后,用VSCode,Goland或其它IDE关上disributed-system-notes/docker/02/go-docker-demo目录。 在该目录下执行如下2条命令,服务失常启动后,会监听8080端口 $ go build main.go$ ./main 在浏览器上输出http://localhost:8080/hello,如果有输入如下后果,就示意所有准备就绪了。 { "msg": "world"}创立Dockerfile在go-docker-demo目录下,创立文件Dockerfile,文件名全称就叫Dockerfile,没有后缀。 Dockerfile文件内容为: FROM golang:latestWORKDIR /app/demoCOPY . .RUN go build main.goEXPOSE 8080ENTRYPOINT ["./main"]FROM: 指定根底镜像。咱们的我的项目须要用到Go,所以指定golang的最新版本为根底镜像 WORKDIR:指定本我的项目在容器里的工作目录或者说存储地位。设置了WORKDIR后,Dockerfile里后续的指令如果要应用容器里的门路,就能够依据WORKDIR来应用相对路径了。 COPY:把执行docker build指定的目录下的某些文件或目录拷贝到容器的指定门路下。例子里的第一个.示意docker build指定的当前目录,第二个.示意容器的当前工作目录WORKDIR,该指令示意把docker build指定的目录下的所有内容(包含子目录下的文件)全副拷贝到容器的/app/demo目录下。 RUN:在指定的容器工作目录执行命令。例子示意在WORKDIR下执行go build main.go,会生成main二进制文件。 EXPOSE:申明容器要应用的端口。 ENTRYPOINT:指定容器的启动程序和参数。 Dockerfile文件语法指引:https://docs.docker.com/engin... 构建镜像在go-docker-demo目录下,执行如下命令来构建镜像: $ docker build -t go-docker-demo .执行实现后,应用docker image ls能够查看到REPOSITORY为go-docker-demo的镜像文件。 运行容器执行如下命令,启动容器: $ docker run -d -p 8080:8080 go-docker-demo胜利执行后,该命令会返回相似2b7a47d1e24265e638a2b931561a303f97463fac9d9f5fa5a9f9b77b2212fa24这样的字符串,这个是运行的容器的ID,也叫container id。 在浏览器上输出http://localhost:8080/hello,如果有输入如下后果,就示意功败垂成了。 { "msg": "world"}容器长啥样通过Docker Desktop里的Containers/Apps这个Tab页找到运行的容器go-docker-demo,点击左边第2个CLI图标,就能够进去到容器里了。 别离执行pwd, ls命令,就能以容器的视角看到以后容器里的文件目录构造。 # pwd/app/demo# lsDockerfile go.mod go.sum main main.go# curl http://127.0.0.1:8080/hello {"msg":"world"}# ls /app boot etc home lib64 mnt proc run srv tmp varbin dev go lib media opt root sbin sys usr容器是被隔离的过程,有本人的文件系统、网络和过程树。 ...

January 5, 2022 · 1 min · jiezi

关于golang:go-httpclient请求流程分析

January 5, 2022 · 0 min · jiezi

关于golang:设计模式的GO实现

随性施展 abstract factory pattern type IProduct interface { show()}type ProductEntity struct {}func (product *ProductEntity) show(){ fmt.Println("product entity")}type IFactory interface { createProduct()(product *ProductEntity)}type Factory struct {}func (factory *Factory) createProduct() (product *ProductEntity) { product = new(ProductEntity) return product}func main() { factory := new (Factory) factory.createProduct().show()}observer pattern type Customer interface { update()}type CustomerEntity struct {}func (*CustomerEntity) update() { fmt.Println("message accepted")}type Producer struct { customers []Customer}func (p *Producer) addCustomer(entity *CustomerEntity) { p.customers = append(p.customers, entity)}func (p Producer) deleteCustomer(entity *CustomerEntity) { // TODO}func (p *Producer) notify() { for _, customer := range p.customers { customer.update() }}

January 5, 2022 · 1 min · jiezi

关于golang:vscode-打造go开发环境

环境设置如下:$ go envset GO111MODULE=onset GOPATH=D:\goset GOPROXY=http://xx.com.cn/goproxyset GOROOT=D:\software\goset GOSUMDB=off装置go插件:go get github.com/mdempsky/gocode go get github.com/uudashr/gopkgs/v2/cmd/gopkgs go get github.com/ramya-rao-a/go-outline go get github.com/acroca/go-symbols go get golang.org/x/tools/cmd/guru go get golang.org/x/tools/cmd/gorename go get github.com/cweill/gotests/... go get github.com/fatih/gomodifytags go get github.com/josharian/impl go get github.com/davidrjenni/reftools/cmd/fillstruct go get github.com/haya14busa/goplay/cmd/goplay go get github.com/go-delve/delve/cmd/dlv go get github.com/stamblerre/gocode go get github.com/rogpeppe/godef go get golang.org/x/tools/cmd/goimports go get golang.org/x/lint/golint go get golang.org/x/tools/gopls执行完下面操作后请从新关上一下vscode 查看装置的程序$ D:\go\bin-rwxr-xr-x 1 root 1049089 14965760 Jul 2 11:31 dlv.exe*-rwxr-xr-x 1 root 1049089 6601216 Aug 21 15:44 fillstruct.exe*-rwxr-xr-x 1 root 1049089 4441088 Aug 21 15:05 go-outline.exe*-rwxr-xr-x 1 root 1049089 4240384 Aug 21 15:05 go-symbols.exe*-rwxr-xr-x 1 root 1049089 11719680 Aug 21 15:05 gocode.exe*-rwxr-xr-x 1 root 1049089 5746176 Aug 21 15:05 godef.exe*-rwxr-xr-x 1 root 1049089 15696896 Aug 21 15:06 godoc.exe*-rwxr-xr-x 1 root 1049089 7433728 Aug 21 15:07 gogetdoc.exe*-rwxr-xr-x 1 root 1049089 7931904 Aug 21 15:25 goimports.exe*-rwxr-xr-x 1 root 1049089 6126592 Aug 21 15:06 golint.exe*-rwxr-xr-x 1 root 1049089 6409728 Aug 21 15:49 gometalinter.exe*-rwxr-xr-x 1 root 1049089 4525568 Aug 21 15:07 gomodifytags.exe*-rwxr-xr-x 1 root 1049089 5326336 Aug 21 15:38 gopkgs.exe*-rwxr-xr-x 1 root 1049089 6258688 Aug 21 15:36 goplay.exe*-rwxr-xr-x 1 root 1049089 6097920 Aug 21 15:11 gorename.exe*-rwxr-xr-x 1 root 1049089 8473088 Aug 21 15:27 goreturns.exe*-rwxr-xr-x 1 root 1049089 12119552 Aug 21 15:30 gotests.exe*-rwxr-xr-x 1 root 1049089 9060864 Aug 21 15:31 guru.exe*-rwxr-xr-x 1 root 1049089 7678464 Aug 21 15:34 impl.exe*settings.json{ "go.formatTool": "goimports", "go.useLanguageServer": true, "[go]": { "editor.snippetSuggestions": "none", "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.organizeImports": true } }, "go.languageServerExperimentalFeatures": { "format": true, "autoComplete": true, "rename": true, "goToDefinition": true, "hover": true, "signatureHelp": true, "goToTypeDefinition": true, "goToImplementation": true, "documentSymbols": true, "workspaceSymbols": true, "findReferences": true, "diagnostics": false },}

January 5, 2022 · 2 min · jiezi

关于golang:Go语言陷阱结构体未导出的字段无法被编解码

咱们来看一段代码 你感觉14、17、22行的输入别离是什么? import ( "encoding/json" "fmt")type Data struct { One int two string three int}func main() { in := Data{1, "two", 3} fmt.Printf("%#v\n", in) encoded, _ := json.Marshal(in) fmt.Println(string(encoded)) var out Data json.Unmarshal(encoded, &out) fmt.Printf("%#v\n", out)}定义构造体type Data struct { One int two string three int}在构造中 英文大写字母结尾的属性是被导出的 而小写字母结尾的属性未导出的 因而 One 属性是被导出的 two、three是未导出的 编码 ... in := Data{1, "two", 3} fmt.Printf("%#v\n", in) //prints main.MyData{One:1, two:"two", three:3} encoded, _ := json.Marshal(in) fmt.Println(string(encoded)) //prints {"One":1} ...在上述2-3行代码,对Data数据结构申明并初始化 ...

January 4, 2022 · 1 min · jiezi

关于golang:Go语言中用-osexec-执行命令的五种姿势

Go语言中用 os/exec 执行命令的五种姿态 残缺系列教程详见:http://golang.iswbm.com 在 Golang 中用于执行命令的库是 os/exec,exec.Command 函数返回一个 Cmd 对象,依据不同的需要,能够将命令的执行分为三种状况 只执行命令,不获取后果执行命令,并获取后果(不辨别 stdout 和 stderr)执行命令,并获取后果(辨别 stdout 和 stderr)第一种:只执行命令,不获取后果#间接调用 Cmd 对象的 Run 函数,返回的只有胜利和失败,获取不到任何输入的后果。 package mainimport ( "log" "os/exec")func main() { cmd := exec.Command("ls", "-l", "/var/log/") err := cmd.Run() if err != nil { log.Fatalf("cmd.Run() failed with %s\n", err) }}第二种:执行命令,并获取后果#有时候咱们执行一个命令就是想要获取输入后果,此时你能够调用 Cmd 的 CombinedOutput 函数。 package mainimport ("fmt""log""os/exec")func main() { cmd := exec.Command("ls", "-l", "/var/log/") out, err := cmd.CombinedOutput() if err != nil { fmt.Printf("combined out:\n%s\n", string(out)) log.Fatalf("cmd.Run() failed with %s\n", err) } fmt.Printf("combined out:\n%s\n", string(out))}CombinedOutput 函数,只返回 out,并不辨别 stdout 和 stderr。如果你想辨别他们,能够间接看第三种办法。 ...

January 4, 2022 · 3 min · jiezi

关于golang:Golang浅谈协程并发竞争资源问题

作者:ReganYue 起源:恒生LIGHT云社区 浅谈协程并发竞争资源问题大家好,这里是致力变得优良的R君,这次咱们持续来进行Golang系列《让咱们一起Golang》,本次咱们来浅谈协程并发竞争资源问题,这也是一个比拟容易了解的知识点,咱们来看一看吧! 咱们在实际操作过程中,往往会遇到领有多条协程并发的状况,那么当多条协程并发时,协程之间是如何竞争无限的资源的呢?本文将介绍无关内容。 咱们先看一看本文实例代码的主函数,两条子协程,主协程3秒后完结。 func main() { go fun1() go fun2() time.Sleep(3 * time.Second)}再看看看两条子协程别离是干些什么吧! func fun1(){ //遍历字符串的每一个字符 for _,c:=range "就像老鼠爱大米"{ //如果这里应用Println的话,输入的会是字符在字符集中的编号。 //这里f是format也就是格局的意思。 fmt.Printf("%c\n",c) //runtime.Goexit() //每隔一纳秒打印一个字。 time.Sleep(time.Nanosecond) }}func fun2(){ for _,c := range"ReganYue"{ fmt.Printf("%c\n",c) //runtime.Goexit() time.Sleep(time.Nanosecond) }}fun1函数,是遍历输入"就像老鼠爱大米",值得注意的是,这里应用for...range循环遍历字符串的话,不能应用 fmt.Println,因为如果这里应用 Println的话,输入的会是字符在字符集中的编号。 而 fmt.Printf 这里f是format也就是格式化的意思。 看看运行后果 R就像eg老鼠an爱Y大米ue发现两条协程运行的后果均匀分布。这就阐明两条协程公平竞争资源,两条协程之间实力旗鼓相当。 可如果激活fun1内的 runtime.Goexit() 那么输入后果就是: 就ReganYue如果激活fun2内的 runtime.Goexit() 那么输入后果就是: 就R像老鼠爱大米因为 Goexit杀掉它的 goroutine,其余 goroutine 也不会受到影响。所以当fun1的所在的子协程被杀死时,不会影响fun2所在的子协程的失常运行。 如果本段代码中两个 runtime.Goexit()都激活,那么两条协程都只会输入一个字符。 就R因为两条协程在输入完一个字符后就被杀死了。 如果两个及以上个协程在没有同步的情景上来访问共享的资源,并且尝试同一时间读和写共享的资源。就会呈现资源竞争问题。呈现的这个问题可能让程序变得略微简单,本文就临时不探讨这些简单状况,想晓得的能够关注博主,博主前期会介绍。 咱们也能够应用 go build 的 -race 参数,应用它能够理解是否存在资源竞争问题,对于 go build 的 -race 参数的应用,本篇博文暂不介绍,前期博主会尽量具体介绍。** ...

January 4, 2022 · 1 min · jiezi

关于golang:Go-通过-MapFilterForEach-等流式-API-高效处理数据

什么是流解决如果有 java 应用教训的同学肯定会对 java8 的 Stream 拍案叫绝,极大的进步了们对于汇合类型数据的解决能力。 int sum = widgets.stream() .filter(w -> w.getColor() == RED) .mapToInt(w -> w.getWeight()) .sum();Stream 能让咱们反对链式调用和函数编程的格调来实现数据的解决,看起来数据像是在流水线一样一直的实时流转加工,最终被汇总。Stream 的实现思维就是将数据处理流程形象成了一个数据流,每次加工后返回一个新的流供应用。 Stream 性能定义入手写代码之前,先想分明,把需要理分明是最重要的一步,咱们尝试代入作者的视角来思考整个组件的实现流程。首先把底层实现的逻辑放一下 ,先尝试从零开始进行性能定义 stream 性能。 Stream 的工作流程其实也属于生产消费者模型,整个流程跟工厂中的生产流程十分类似,尝试先定义一下 Stream 的生命周期: 创立阶段/数据获取(原料)加工阶段/两头解决(流水线加工)汇总阶段/终结操作(最终产品)上面围绕 stream 的三个生命周期开始定义 API: 创立阶段为了创立出数据流 stream 这一形象对象,能够了解为结构器。 咱们反对三种形式结构 stream,别离是:切片转换,channel 转换,函数式转换。 留神这个阶段的办法都是一般的公开办法,并不绑定 Stream 对象。 // 通过可变参数模式创立 streamfunc Just(items ...interface{}) Stream// 通过 channel 创立 streamfunc Range(source <-chan interface{}) Stream// 通过函数创立 streamfunc From(generate GenerateFunc) Stream// 拼接 streamfunc Concat(s Stream, others ...Stream) Stream加工阶段加工阶段须要进行的操作往往对应了咱们的业务逻辑,比方:转换,过滤,去重,排序等等。 ...

January 4, 2022 · 9 min · jiezi

关于golang:彻底明白Go语言的Channel了

channel 概述Hello 大家好!咱们又见面了,本文咱们一起搞懂 Go语言中 channel 及channel底层实现和一些常见面试题。 channel 是 Go 语言内建的first-class类型,也是 Go 语言不同凡响的个性之一。先看一个利用场景,比方协程A执行过程中须要创立子协程A1、A2 ... An,协程A创立完子协程后就期待子协程退出,这样场景的Go为咱们提供三种解决方案: 应用 channel 管制子协程waitGroup 信号量机制管制子协程Context 应用上下文管制子协程它们三种解决方案各有优劣,比方:应用 channel 来管制子协程长处实现简略,毛病就是当须要大量创立协程时就须要有雷同数量的 channel,这样对于子协程持续派生进去的协程就不不便管制。 首先,想一想,为什么 Go 引入channel,及channel能为咱们提供解决怎么样的问题?理解 channel 能够从CSP 模型理解,CSP模型是 Tony Hoare 在1978年发表的论文中,CSP次要讲一种并发编程语言,CSP 容许应用过程组建来形容零碎,它们独立运行,并且只通过消息传递的形式通信。这篇论文是对 Go 创始人Rob Pike 对Go语言并发设计的产生微小影响,最初通过引入 channel 这种新的类型,来实现 CSP 的思维。 在应用 channel 类型时候,你无需引入某个包,就能应用它,它就是 Go 语言内置的类型,不像其余库,你必须的引入sync包货atomic 包能力应用它们。 channel 根本用法channel 很多人常说所谓的 通道,那么通道也是咱们生存中相似的管道,用来传输货色。计算机能够应用通道来进行通信,在Go语言中,常见的容许 Goroutine 之间进行数据传输。在传输中,你须要明确一些规定,首先,每个通道只容许替换指定类型的数据,也称为通道元素类型(相似生存中,自家水管只容许运输能喝的水,运输汽油,你须要应用另一个管道)。在 Go 语言中,应用chan 关键字来申明一个新通道,应用 close() 函数来敞开通道。 定义好通道,能够往 channel 发送数据,从channel中接收数据,你还能够定义 只能承受、只能发送、也能够承受又能够发送 三种类型。 申明通道类型格局如下: var 变量 chan 元素类型例子 var ch1 chan int // 申明一个传递整型的通道var ch3 chan []int // 申明一个传递int切片的通道创立 channel : ...

January 3, 2022 · 5 min · jiezi

关于golang:Go开发工程师迎接上升风口踏入蓝海行业完结feess

download:Go开发工程师:迎接回升风口,踏入蓝海行业!【完结】问题形容囚徒窘境是博弈论中经典问题,有两个囚徒有瞒哄未报的盗窃案件,在审讯过程中每个囚徒能够抉择抗拒不抵赖或者坦率抵赖。局势就是两个囚徒给出本人策略算一个局势,那么依据排列组合局势有 抗拒,抗拒坦率,抗拒抗拒,坦率坦率,坦率如果两个人都抗拒不抵赖每人会被判 1 年,如果两个人都坦率每个人会被判 3 年,如果一方坦率另一方抗拒,抗拒一方会被判 5 年而坦率会被开释。 局中人:两个囚徒 策略抗拒或者坦率 效用函数矩阵每个人都会抉择最大化本人受害的最大化策略,那么对于囚徒最大化受害就是服刑工夫最短,为了这个目标怎么的策略才是感性的呢? 对于囚徒(A 囚徒)做出策略时还须要思考到另一个囚徒(B 囚徒)的策略抉择,那么 B 囚徒抉择有两种可能别离是抗拒或者是坦率,这里就称为 B 囚徒,如果 B 囚徒坦率的前提,A 囚徒如果坦率将服刑 3 年如果抗拒则服刑 5 年,所以 A 最佳抉择是认罪。 假如后面策略 A 囚徒抉择了抗拒状况,B 囚徒抉择坦率收益为 0,当 A 囚徒抉择坦率状况,B 囚徒也会抉择坦率获取去收益最大。 对于 A 囚徒无论 B 囚徒做出什么策略,坦率都是 A 囚徒的占优策略。两个囚徒都不能通过单方面扭转策略来减少本人的效益,因而谁都没有游离这个策略组合的动机。 占优策略在抉择策略时,有一个策略的效用总是大于其余所有策略效用时,咱们就把这类策略称为占优策略(Dominant Strategy) 占优策略纳什平衡当所有参与者的最优回应是抉择他们的占优策略时,这时达到的纳什平衡称为占优策略纳什平衡。

January 2, 2022 · 1 min · jiezi

关于golang:极客时间Go进阶训练营全新升级第4期fdsz

download:极客工夫-Go进阶训练营|全新降级第4期问题形容囚徒窘境是博弈论中经典问题,有两个囚徒有瞒哄未报的盗窃案件,在审讯过程中每个囚徒能够抉择抗拒不抵赖或者坦率抵赖。局势就是两个囚徒给出本人策略算一个局势,那么依据排列组合局势有 抗拒,抗拒坦率,抗拒抗拒,坦率坦率,坦率如果两个人都抗拒不抵赖每人会被判 1 年,如果两个人都坦率每个人会被判 3 年,如果一方坦率另一方抗拒,抗拒一方会被判 5 年而坦率会被开释。 局中人:两个囚徒 策略抗拒或者坦率 效用函数矩阵每个人都会抉择最大化本人受害的最大化策略,那么对于囚徒最大化受害就是服刑工夫最短,为了这个目标怎么的策略才是感性的呢? 对于囚徒(A 囚徒)做出策略时还须要思考到另一个囚徒(B 囚徒)的策略抉择,那么 B 囚徒抉择有两种可能别离是抗拒或者是坦率,这里就称为 B 囚徒,如果 B 囚徒坦率的前提,A 囚徒如果坦率将服刑 3 年如果抗拒则服刑 5 年,所以 A 最佳抉择是认罪。 假如后面策略 A 囚徒抉择了抗拒状况,B 囚徒抉择坦率收益为 0,当 A 囚徒抉择坦率状况,B 囚徒也会抉择坦率获取去收益最大。 对于 A 囚徒无论 B 囚徒做出什么策略,坦率都是 A 囚徒的占优策略。两个囚徒都不能通过单方面扭转策略来减少本人的效益,因而谁都没有游离这个策略组合的动机。 占优策略在抉择策略时,有一个策略的效用总是大于其余所有策略效用时,咱们就把这类策略称为占优策略(Dominant Strategy) 占优策略纳什平衡当所有参与者的最优回应是抉择他们的占优策略时,这时达到的纳什平衡称为占优策略纳什平衡。

January 2, 2022 · 1 min · jiezi

关于golang:gRPCGo入门教程

protobuf简介Protocol Buffers(protobuf):与编程语言无关,与程序运行平台无关的数据序列化协定以及接口定义语言(IDL: interface definition language)。 要应用protobuf须要先了解几个概念: protobuf编译器protoc,用于编译.proto文件 开源地址:https://github.com/protocolbu...编程语言的protobuf插件,搭配protoc编译器,依据.proto文件生成对应编程语言的代码。protobuf runtime library:每个编程语言有各自的protobuf runtime,用于实现各自语言的protobuf协定。Go语言的protobuf插件和runtime library有过2个版本: 第1个版本开源地址:https://github.com/golang/protobuf,蕴含有插件proto-gen-go,能够生成xx.pb.go和xx_grpc.pb.go。Go工程里导入该版本的protobuf runtime的形式如下: import "github.com/golang/protobuf"第2个版本开源地址:https://github.com/protocolbuffers/protobuf-go,同样蕴含有插件proto-gen-go。不过该项目标proto-gen-go从v1.20版本开始,不再反对生成gRPC服务定义,也就是xx_grpc.pb.go文件。要生成gRPC服务定义须要应用grpc-go里的progo-gen-go-grpc插件。Go工程里导入该版本的protobuf runtime的形式如下: import "google.golang.org/protobuf"举荐应用第2个版本,对protobuf的API做了优化和精简,并且把工程界线分分明了: 第一,把protobuf的Go实现都放在protobuf的我的项目里,而不是放在golang语言我的项目上面。第二,把gRPC的生成,放在grpc-go我的项目里,而不是和protobuf runtime混在一起。有的老我的项目可能应用了第1个版本的protobuf runtime,在老我的项目里开发新性能的时候也能够应用第2个版本protobuf runtime,反对2个版本在一个Go我的项目里共存。然而要留神:一个我的项目里同时应用2个版本必须保障第一个版本的版本号不低于v1.4。 gRPC-Go简介gRPC-Go: gRPC的Go语言实现,基于HTTP/2的RPC框架。 开源地址:https://github.com/grpc/grpc-go Go我的项目里导入该模块的形式如下: import "google.golang.org/grpc"grpc-go我的项目里还蕴含有protoc-gen-go-grpc插件,用于依据.proto文件生成xx_grpc.pb.go文件。 环境装置分为3步: 装置Go 步骤参考:https://go.dev/doc/install装置Protobuf编译器protoc: 用于编译.proto 文件 步骤参考:https://grpc.io/docs/protoc-i...执行如下命令查看protoc的版本号,确认版本号是3+,用于反对protoc3 protoc --version装置protoc编译器的Go语言插件 protoc-gen-go插件:用于生成xx.pb.go文件 go install google.golang.org/protobuf/cmd/protoc-gen-go@latestprotoc-gen-go-grpc插件:用于生成xx_grpc.pb.go文件 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest留神:有的教程可能只让你装置protoc-gen-go,没有装置protoc-gen-go-grpc,那有2种状况: 应用的是第1个版本github.com/golang/protobuf的protoc-gen-go插件。应用的是第2个版本google.golang.org/protobuf的protoc-gen-go插件并且protoc-gen-go版本号低于v1.20。从v1.20开始,第2个版本的protoc-gen-go插件不再反对生成gRPC服务定义。上面是官网阐明:The v1.20 protoc-gen-go does not support generating gRPC service definitions. In the future, gRPC service generation will be supported by a new protoc-gen-go-grpc plugin provided by the Go gRPC project. ...

January 2, 2022 · 2 min · jiezi

关于golang:Go编译原理系列3词法分析

前言在上一篇文章中,介绍了词法剖析中的核心技术,有穷自动机(DFA),以及两个常见的词法分析器的应用及工作原理。在这个根底下来看Go的词法剖析源码会轻松许多 本文次要蕴含以下内容: Go编译的入口文件,以及在编译入口文件中做了哪些事件词法剖析处在Go编译的什么地位,以及具体过程是什么样的写一个测试的go源文件,对这个源文件进行词法剖析,并获取到词法剖析的后果源码剖析Go的编译入口为了能更分明的理解Go的编译过程是如何走到词法剖析这一步的,这里先介绍Go的编译入口文件在什么中央,以及大抵做了哪些事件 Go的编译入口文件在:src/cmd/compile/main.go -> gc.Main(archInit)进入到gc.Main(archInit)这个函数,这个函数内容比拟长,它前边局部做的事件次要是获取命令行传入的参数并更新编译选项和配置。而后你会看到下边这行代码 lines := parseFiles(flag.Args())这就是词法剖析和语法分析的入口,它会对传入的文件进行词法和语法分析,失去的是一棵语法树,后边就会将它构建成形象语法树,而后对它进行类型查看等操作,会在后边的文章中分享 关上parseFiles(flag.Args())文件,能够看到如下内容(我省略了后边局部的代码,次要看词法剖析这块的内容): func parseFiles(filenames []string) uint { noders := make([]*noder, 0, len(filenames)) // Limit the number of simultaneously open files. sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10) for _, filename := range filenames { p := &noder{ basemap: make(map[*syntax.PosBase]*src.PosBase), err: make(chan syntax.Error), } noders = append(noders, p) go func(filename string) { sem <- struct{}{} defer func() { <-sem }() defer close(p.err) base := syntax.NewFileBase(filename) f, err := os.Open(filename) if err != nil { p.error(syntax.Error{Msg: err.Error()}) return } defer f.Close() p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error }(filename) } ......}咱们晓得,在Go的编译过程中,最终每一个源文件,都会被解析成一棵语法树,从上边代码的前几行就能看进去,它首先会创立多个协程去编译源文件,然而每次是有限度关上的源文件数的 ...

January 2, 2022 · 6 min · jiezi

关于golang:Goroutine调度器及面试精选

Goroutine调度器Go语言在并发编程有着十分弱小的能力,讲到调度器,咱们的话题离不开操作系统、过程与线程这些概念,在学习操作系统时,线程是操作系统调度的最根本单元。 在没有学习Go语言之前,线程之间通信,通过内存共享能够实现,然而在调度时每个线程都会占用1M以上内存空间,还有复原寄存器中内容也须要向操作系统申请或销毁资源,这样会有较大额定开销。 在Go语言中,不须要通过共享内存来通信,而是通过通信来共享内存,这也是Go语言最重要的编程理念。这样的话,Go调度器对Goroutine的上下文切换就缩小额定开销了。 Go 调度器概念 G(Goroutine) — 示意 Go协程,它是一个待执行的工作或代表一个Goroutine对象;M(Machine) — 示意操作系统的线程,它由操作系统的调度器调度和治理;P(Processor) — 示意处理器,它能够被看做运行在线程上的本地调度器;M必须领有P才能够执行G中的代码,P含有一个蕴含多个G的队列,P能够调度G交由M执行。P的个数在启动时就决定,默认是应用等同CPU的数量,又因为M必须持有一个P能力运行Go代码,所有M个数个别也是等同于CPU个数,以达到尽可能的应用CPU而又不至于产生过多的线程切换开销,这样就大大降低操作系统和硬件的负载。P的个数,能够应用runtime.GOMAXPROCS()来设置个数,当在IO密集的场景下能够自行设置来进步性能。 Go 语言的调度器是一个非常复杂机制,看了Go源码,尽管有很多正文,然而对于工作经验不足或刚入门Go开发来说,咱们还是须要多多的深钻研,还有很多细节须要去学习,比方,调度器的设计原理: 在早起0.x版本中Go语言调度器是单线程调度器,由G-M模型组成,还有P这个概念;通过一直优化与设计,到1.0版本就引入多线程调度器,然而呈现全局锁导致竞争重大;到1.1版本,引入处理器P,而后就形成GMP模型;到Go 1.2 退出抢占式调度器;以及到1.14版本引入基于信号量的抢占式调度器面试题: Go 中的GMP模型理解吗?GMP模型Go有几种状态?(闲暇、待运行、运行中、零碎调用、期待中、已进行及栈复制中)为什么Go能进步性能,与过程和线程有什么区别? 线程和过程会导致CPU额定开销大,切换线程上下文及申请销毁都须要额定开销;线程占用内存个别是固定为2M内存空间;Go 栈内存是可变的,初始的时候个别为2KB,最大可扩大为1GB;Go 本人实现的调度器,所以创立和销毁开销小;

January 2, 2022 · 1 min · jiezi

关于golang:Golang-学习笔记

## Golang根底> 起源Bilibili IT营 大地老师学习视频:[点我传送](https://www.bilibili.com/video/BV14T4y1g7h9)- [Go语言的装置](./Golang根底/0_Go语言的装置)- [Go语言倒退简史](./Golang根底/1_Go语言倒退简史)- [Go的变量](./Golang根底/2_Go的变量)- [Go的数据类型](./Golang根底/3_Go的数据类型)- [Go的运算符](./Golang根底/4_Go的运算符)- [Go的流程管制](./Golang根底/5_Go的流程管制)- [Go的数组](./Golang根底/6_Go的数组)- [Go的切片](./Golang根底/7_Go的切片)- [Go的map](./Golang根底/8_Go的map)- [Go的函数](./Golang根底/9_Go的函数)- [Go中的日期函数](./Golang根底/10_Go中的日期函数)- [Go中的指针](./Golang根底/11_Go中的指针)- [Go中的构造体](./Golang根底/12_Go中的构造体)- [Go中的包以及GoMod](./Golang根底/13_Go中的包以及GoMod)- [Go中的接口](./Golang根底/14_Go中的接口)- [goroutine实现并行和并发](./Golang根底/15_goroutine实现并行和并发)- [Golang中的反射](./Golang根底/16_Golang中的反射)- [源码](./Golang根底/Code)## Golang进阶- [Golang并发编程](./Golang进阶/4_Golang并发编程)- [互联网协议介绍](./Golang进阶/5_互联网协议介绍)- [HTTP申请](./Golang进阶/6_HTTP申请)- [日志库](./Golang进阶/7_日志库)- [反射](./Golang进阶/8_反射)- [单元测试](./Golang进阶/9_单元测试)- [Flag包的用法](./Golang进阶/10_Flag包的用法)- [Go操作数据库](./Golang进阶/11_Go操作数据库)- [sqlx库的应用](./Golang进阶/12_sqlx库的应用)- [Go操作Redis](./Golang进阶/13_Go操作Redis)- [Go操作音讯队列](./Golang进阶/14_Go操作音讯队列)- [Go的依赖治理GoModule](./Golang进阶/15_Go的依赖治理GoModule)- [GoContext的治理](./Golang进阶/16_GoContext的治理)- [日志收集我的项目架构设计及kafka介绍](./Golang进阶/17_日志收集我的项目架构设计及kafka介绍)- [etcd介绍](./Golang进阶/18_etcd介绍)- [ES介绍和应用](./Golang进阶/19_ES介绍和应用)- [Kafka生产实例](./Golang进阶/20_Kafka生产实例)- [Kibana介绍和应用](./Golang进阶/21_Kibana介绍和应用)- [Prometheus和Grafana介绍](./Golang进阶/22_Prometheus和Grafana介绍)## Gin框架- [Gin内容介绍](./Gin框架/1_Gin内容介绍)- [http及Template介绍](./Gin框架/2_http及Template介绍)- [GORM介绍和应用](./Gin框架/3_GORM介绍和应用)- [GORM进行CURD](./Gin框架/4_GORM进行CURD)## K8S详解教程- [kubernetes命令](./k8s具体教程/kubernetes命令)- [Kubernetes具体教程](./k8s具体教程/Kubernetes具体教程)## Redis具体教程- [Redis学习笔记](./Redis具体教程/Redis学习笔记-高级阶段)- [Redis学习笔记-高级阶段](./Redis具体教程/Redis学习笔记-高级阶段)## Go-Zero学习 - [go-zero架构设计](./go-zero学习/1_go-zero架构设计)- [go-zero介绍](./go-zero学习/2_go-zero介绍)- [go-zero实用场景](./go-zero学习/3_go-zero实用场景)- [应用goctl疾速创立我的项目](./go-zero学习/4_应用goctl疾速创立我的项目)- [应用goctl创立微服务项目](./go-zero学习/5_应用goctl创立微服务项目)

December 31, 2021 · 1 min · jiezi

关于golang:zookeeper集群环境部署

zookeeper集群环境搭建本文B站视频教程:https://www.bilibili.com/vide... 关注微信,学习更多... 批改配置文件,增加集群ipserver.1=192.168.18.128:2888:3888server.2=192.168.18.138:2888:3888server.3=192.168.18.148:2888:3888server.A=B:C:D A:其中 A 是一个数字,示意这个是服务器的编号; B:是这个服务器的 ip 地址; C:Zookeeper服务器之间的通信端口; D:Leader选举的端口。 批改log data 门路dataDir=/var/zkdata创立myid在dataDir目录上面创立myid文件,内容为对应的服务器id 例如 1 2 3 echo 1 > /var/zkdata/myid查看集群状态如果一个为leader,另外两个为follower就对了 有时候须要重启服务器 reboot启动命令: zkServer.sh start查看集群节点状态: zkServer.sh status查看以后服务器是leader 还是follower本文B站视频教程:https://www.bilibili.com/vide... 关注微信,学习更多...

December 31, 2021 · 1 min · jiezi

关于golang:kafka集群配置

kafka集群配置本文B站视频教程: https://www.bilibili.com/vide... 关注微信,学习更多... zookeeper集群环境搭建批改配置文件,增加集群ipserver.1=192.168.18.128:2888:3888server.2=192.168.18.138:2888:3888server.3=192.168.18.148:2888:3888server.A=B:C:D A:其中 A 是一个数字,示意这个是服务器的编号; B:是这个服务器的 ip 地址; C:Zookeeper服务器之间的通信端口; D:Leader选举的端口。 批改log data 门路dataDir=/var/zkdata创立myid在dataDir目录上面创立myid文件,内容为对应的服务器id 例如 1 2 3 echo 1 > /var/zkdata/myid查看集群状态如果一个为leader,另外两个为follower就对了 有时候须要重启服务器 reboot启动命令: zkServer.sh start查看集群节点状态: zkServer.sh status查看以后服务器是leader 还是follower配置kafka集群批改server.properties配置文件批改broker.id ,每台服务器都不一样,最好跟zookeeper myid雷同。批改log.dirs门路。批改zookeeper集群门路 zookeeper.connect=192.168.18.128:2181,192.168.18.138:2181,192.168.18.148:2181如果zookeeper和kafka都启动过,删除他们的旧的日志,否则会报如下谬误ERROR Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer) kafka.common.InconsistentClusterIdException: The Cluster ID Reu8ClK3TTywPiNLIQIm1w doesn't match stored clusterId Some(BaPSk1bCSsKFxQQ4717R6Q) in meta.properties. The broker is trying to join the wrong cluster. Configured zookeeper.connect may be wrong. at kafka.server.KafkaServer.startup(KafkaServer.scala:220) at kafka.server.KafkaServerStartable.startup(KafkaServerStartable.scala:44) at kafka.Kafka$.main(Kafka.scala:84) at kafka.Kafka.main(Kafka.scala)本文B站视频教程: https://www.bilibili.com/vide... ...

December 31, 2021 · 1 min · jiezi

关于golang:Go-Quiz-从Go面试题看defer的注意事项第2篇

面试题这是Go Quiz系列的第5篇,是考查Go语言的defer语义,也是defer语义的第2篇。 没有看过defer第1篇的能够先回顾下:Go defer语义第1篇。 本文的题目如下: package mainfunc bar() (r int) { defer func() { r += 4 if recover() != nil { r += 8 } }() var f func() defer f() f = func() { r += 2 } return 1}func main() { println(bar())}A: 1B: 7C: 12D: 13E: 15这道题相比于defer第1篇的题目,次要考查以下知识点: 被defer的函数的值是什么时候确定的?留神:这里说的是函数值,不是函数的参数。如果函数的值是nil,那defer一个nil函数是什么后果?多个被defer的函数的执行先后顺序,遵循LIFO准则。defer 和recover联合能够捕捉panic。defer如果对函数的命名返回值参数做批改,有什么影响?解析函数值下面提到了函数值的概念,对应的英文是function value。可能刚学习Go的同学还不太理解,我先解说下这个概念。 首先,函数和struct,int等一样,也是一个类型(type)。 咱们能够先定义一个函数类型,再申明一个该函数类型的变量,并且给该变量赋值。该函数类型变量的值咱们就能够叫做函数值。看上面的代码示例就高深莫测了。 package mainimport "fmt"// 函数类型FuncTypetype FuncType func(int) int// 定义变量f1, 类型是FuncTypevar f1 FuncType = func(a int) int { return a }// 定义变量f, 类型是一个函数类型,函数签名是func(int) int// 在main函数里给f赋值,零值是nilvar f func(int) intfunc main() { fmt.Println(f1(1)) // 定义变量f2,类型是FuncType var f2 FuncType f2 = func(a int) int { a++ return a } fmt.Println(f2(1)) // 给函数类型变量f赋值 f = func(a int) int { return 10 } fmt.Println(f(1))}咱们平时实现函数的时候,通常是把函数的类型定义,函数变量和变量赋值一起做了。 ...

December 30, 2021 · 2 min · jiezi

关于golang:谈谈Golang的同步等待组

作者:ReganYue 起源:恒生LIGHT云社区 大家好,这里是致力变得优良的R君,这次咱们持续来进行Golang系列《让咱们一起Golang》,区块链系列内容明年会持续更新,共识算法曾经根本结束,如果不出意外,除夕那个星期就是介绍如何构建公链我的项目了,本次咱们来理解Golang的同步期待组,这也是一个比拟容易了解的知识点,咱们来看一看吧! 咱们当初开十条子协程,而后当十条子协程全副完结后,主协程立马完结。动动你的小脑袋,想一想应该怎么做?如果是一条子协程的话就很容易实现,当这条子协程完结时让主协程完结就行了。然而咱们当初是10条,让任何一条子协程公布让主协程完结的命令都不行,因为你无奈确定哪一条子协程是最初完结的。所以咱们当初用上了期待组。 期待组是什么原理呢?发明一个子协程就注销一下,而后子协程干完活就将其除名,名单除洁净了就完结主协程。 咱们来看看期待组的无关示例: func main() { fmt.Println(time.Now()) var wg sync.WaitGroup //起一个协程就加一 wg.Add(1) go func() { for i:=0;i<5;i++{ fmt.Println(i) //相当于阻塞一秒,读到工夫 <- time.After(time.Second) } fmt.Println(time.Now()) //活干完之后减一 wg.Done() }() wg.Add(1) go func() { var i int ticker := time.NewTicker(time.Second) for{ <- ticker.C i++ fmt.Println("秒表",i) if i>9 { break } } fmt.Println(time.Now()) wg.Done() }() //期待组阻塞期待至记录清零为止 wg.Wait() fmt.Println("END")}这段代码是建设一条协程就应用wg.Add(1)给期待组加一,而后活干完之后就减一。 WaitGroup 期待一组 goroutine 实现。主 goroutine 调用 Add 来增加要期待的 goroutine 的数量。 而后每个 goroutine 运行并在实现时调用 Done。 同时,Wait 可用于阻塞,直到所有 goroutine 实现。 ...

December 30, 2021 · 1 min · jiezi

关于golang:开源-GoravelGolang-Web-框架-新增-Cache-模块

对于 GoravelGoravel 是一个性能齐备、具备良好扩大能力的 Web 应用程序框架。 作为一个起始脚手架帮忙 Golang 开发者疾速构建本人的利用。我的项目地址:https://github.com/goravel/goravel欢送 star 与 issues :) 缓存模块介绍Goravel 提供了可拓展的缓存模块。该模块能够应用 facades.Cache 进行操作。 配置在 config/cache.php 中进行所有自定义配置。容许配置不同的缓存驱动,默认应用 redis,你也能够自定义驱动,能够进入配置文件进行查看。 可用的缓存驱动名称形容redisRedis 驱动custom自定义驱动缓存应用从缓存中获取数据value := facades.Cache.Get("goravel", func() interface{} { return "default"})你能够传递一个 func 作为默认值。如果指定的数据在缓存中不存在,将返回 func 的后果。传递闭包的办法容许你从数据库或其余内部服务中获取默认值。留神闭包构造 func() interface{}。 value := facades.Cache.Get("goravel", func() interface{} { return "default"})查看缓存项是否存在value := facades.Cache.Has("goravel")获取和存储有时你可能想从缓存中获取一个数据,而当申请的缓存项不存在时,程序能为你存储一个默认值。 value, err := facades.Cache.Remember("goravel", 5 * time.Second, func() interface{} { return "goravel"})如果缓存中不存在你想要的数据时,则传递给 Remember 办法的闭包将被执行,而后将其后果返回并搁置到缓存中。 你能够应用 RememberForever 办法从缓存中获取数据或者永恒存储它: value, err := facades.Cache.RememberForever("goravel", func() interface{} { return "default"})获取和删除value := facades.Cache.Pull("goravel", "default")在缓存中存储数据err := facades.Cache.Put("goravel", "value", 5 * time.Second)如果缓存的过期工夫设置为 0, 则缓存将永恒无效: ...

December 29, 2021 · 2 min · jiezi

关于golang:实用golang日志库logger集成了日志及分布式链路追踪功能

loggerloggerlogger wraps uber/zap and trace with opentelemetry Feature[X] 反对日志及切分[X] 反对追踪(基于 opentelemetry)[X] 反对 Debug,Info,Warn,Error,Fatal 日志等级[X] 反对异样主动复原 defer logger.End(ctx)Installgo get -u -v github.com/itmisx/loggerUsage配置项 type Config struct { // 调试模式,默认仅记录谬误 Debug bool `yaml:"debug" mapstructure:"debug"` // 日志文件记录开关 EnableLog bool `yaml:"enable_log" mapstructure:"enable_log"` // 日志追踪开关 EnableTrace bool `yaml:"enable_trace" mapstructure:"enable_trace"` // 日志文件门路 File string `yaml:"file" mapstructure:"file"` // 单个日志文件的大小限度,单位MB MaxSize int `yaml:"max_size" mapstructure:"max_size"` // 日志文件数据的限度 MaxBackups int `yaml:"max_backups" mapstructure:"max_backups"` // 日志文件的保留天数 MaxAge int `yaml:"max_age" mapstructure:"max_age"` // 日志文件压缩开关 Compress bool `yaml:"compress" mapstructure:"compress"` // 日志切分的工夫,参考linux定时工作0 0 0 * * *,准确到秒 Rotate string `yaml:"rotate" mapstructure:"rotate"` // 追踪内容导出类型,默认为jaeger TracerProviderType string `yaml:"tracer_provider_type" mapstructure:"tracer_provider_type"` // 追踪采样的频率, 0.0-1 TraceSampleRatio float64 `yaml:"trace_sample_ratio" mapstructure:"trace_sample_ratio"` // jaeger的URI地址 JaegerServer string `yaml:"jaeger_server" mapstructure:"jaeger_server"` // jaeger用户名 JaegerUsername string `yaml:"jaeger_username" mapstructure:"jaeger_username"` // jaeger明码 JaegerPassword string `yaml:"jaeger_password" mapstructure:"jaeger_password"`}初始化 ...

December 29, 2021 · 2 min · jiezi

关于golang:Go-Quiz-从Go面试题看defer语义的底层原理和注意事项

面试题这是Go Quiz系列的第4篇,对于Go语言的defer语义。 这道题略微有点迷惑性,通过这道题能够加深咱们对Go语言defer关键字底层运行机制的了解。 package maintype Foo struct { v int}func NewFoo(n *int) Foo { print(*n) return Foo{}}func (Foo) Bar(n *int) { print(*n)}func main() { var x = 1 var p = &x defer NewFoo(p).Bar(p) x = 2 p = new(int) NewFoo(p)}A: 100B: 102C: 022D: 011这道题次要考查以下知识点: 被defer的函数或办法什么时候执行?被defer的函数或办法的参数的值是什么时候确定的?被defer的函数或办法如果存在多级调用是什么机制?比方本题的NewFoo(p).Bar(p)就存在二级调用,先调用了NewFoo函数,再调用了Bar办法。解析咱们再看看官网文档怎么说的: Each time a "defer" statement executes, the function value and parameters tothe call are evaluated as usual and saved anew but the actual function is not invoked. ...

December 29, 2021 · 2 min · jiezi

关于golang:如何在-Go-中将-byte-转换为-ioReader

原文链接: [如何在 Go 中将 []byte 转换为 io.Reader?](https://mp.weixin.qq.com/s/nF...) 在 stackoverflow 上看到一个问题,题主进行了一个网络申请,接口返回的是 []byte。如果想要将其转换成 io.Reader,须要怎么做呢? 这个问题解决起来并不简单,简略几行代码就能够轻松将其转换胜利。不仅如此,还能够再通过几行代码反向转换回来。 上面听我缓缓给你吹,首先间接看两段代码。 []byte 转 io.Readerpackage mainimport ( "bytes" "fmt" "log")func main() { data := []byte("Hello AlwaysBeta") // byte slice to bytes.Reader, which implements the io.Reader interface reader := bytes.NewReader(data) // read the data from reader buf := make([]byte, len(data)) if _, err := reader.Read(buf); err != nil { log.Fatal(err) } fmt.Println(string(buf))}输入: Hello AlwaysBeta这段代码先将 []byte 数据转换到 reader 中,而后再从 reader 中读取数据,并打印输出。 ...

December 29, 2021 · 2 min · jiezi

关于golang:Go-Quiz-从Go面试题看分号规则和switch的注意事项

面试题这是Go Quiz系列的第3篇,对于Go语言的分号规定和switch的个性。 这道题比拟tricky,通过这道题能够加深咱们对Go语言里的分号:规定和switch个性的了解。 package mainfunc f() bool { return false}func main() { switch f() { case true: println(1) case false: println(0) default: println(-1) }}A: 1B: 0C: -1这道题次要考查以下知识点: Go语言里的分号:规定switch前面的{换行后编译器会在背地做什么?解析Go语言和C++一样,在每行语句(statement)的开端是以分号:结尾的。 看到这里,你可能会有点懵,是不是在想:我写Go代码的时候也没有在语句开端加分号啊。。。 那是因为Go编译器的词法解析程序主动帮你做了这个事件,在须要加分号的中央给你加上了分号。 如果你在代码里显示地加上分号,编译器是不会报错的,只是Go不须要也不倡议显示加分号,所有交给编译器去主动实现。 那编译器是怎么往咱们代码里插入分号:的呢?规定是什么?咱们看看官网文档的说法: When the input is broken into tokens, a semicolon is automatically inserted into the token stream immediately after a line's final token if that token is an identifieran integer, floating-point, imaginary, rune, or string literalone of the keywords break, continue, fallthrough, or returnone of the operators and punctuation ++, --, ), ], or }To allow complex statements to occupy a single line, a semicolon may be omitted before a closing ")" or "}".依据这2个规定,咱们来剖析下本文最开始的题目,switch代码如下所示: ...

December 28, 2021 · 2 min · jiezi

关于golang:使用三大核心语言JavaPythonGolang玩转zookeeper

本文视频教程https://www.bilibili.com/vide... 关注公众号 学习更多精彩课程 应用三大外围语言Java、Python、Golang玩转zookeeper应用Java原生api操作zookeeper创立一个maven我的项目创立一个maven我的项目 增加我的项目依赖<dependencies> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.8</version> </dependency></dependencies>https://mvnrepository.com/实现代码package com.duoke360;import org.apache.zookeeper.*;import java.io.IOException;import java.util.concurrent.CountDownLatch;public class Test { public static void main(String[] args) throws IOException, InterruptedException, KeeperException { String connStr = "192.168.18.128:2181"; CountDownLatch countDown = new CountDownLatch(1); Watcher watcher= event -> { if (event.getState() == Watcher.Event.KeeperState.SyncConnected) { System.err.println("eventType:"+event.getType()); if(event.getType()== Watcher.Event.EventType.None){ countDown.countDown(); }else if(event.getType()== Watcher.Event.EventType.NodeCreated){ System.out.println("listen:节点创立"); }else if(event.getType()== Watcher.Event.EventType.NodeChildrenChanged){ System.out.println("listen:子节点批改"); } } }; ZooKeeper zookeeper = new ZooKeeper(connStr, 5000,watcher); countDown.await(); //注册监听,每次都要从新注册,否则监听不到 // 先创立一个根节点root zookeeper.exists("/root/ghz", watcher); // 创立节点 String result = zookeeper.create("/root/ghz", "老郭".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println(result); Thread.sleep(10); // 获取节点 byte[] bs = zookeeper.getData("/root/ghz", true, null); result = new String(bs); System.out.println("创立节点后的数据是:" + result); // 批改节点 zookeeper.setData("/root/ghz", "多课网-老郭".getBytes(), -1); Thread.sleep(10); bs = zookeeper.getData("/root/ghz", true, null); result = new String(bs); System.out.println("批改节点后的数据是:" + result); // 删除节点 zookeeper.delete("/root/ghz", -1); System.out.println("节点删除胜利"); }}运行后果eventType:NoneeventType:NodeCreatedlisten:节点创立/root/ghz创立节点后的数据是:老郭eventType:NodeDataChanged批改节点后的数据是:多课网-老郭节点删除胜利eventType:NodeDeleted应用java zkclient库操作zookeeper.md创立一个maven我的项目创立一个maven我的项目 ...

December 28, 2021 · 4 min · jiezi

关于golang:简单的-for-循环也会踩的坑

前言最近实现某个业务时,须要读取数据而后再异步解决;在 Go 中实现起来天然就比较简单,伪代码如下: list := []*Demo{{"a"}, {"b"}} for _, v := range list { go func() { fmt.Println("name="+v.Name) }() } type Demo struct { Name string }<!--more--> 看似非常简单几行代码却和咱们的预期不符,打印之后输入的是: name=bname=b并不是咱们预期的: name=aname=b坑一因为写 go 的资格尚浅、道行更是肤浅,这 bug 我硬是找了个把小时;刚开始还认为是数据源的问题,经验了好几轮自我狐疑。总之过程先不表,先看看如何修复这个问题。 首先第一种方法是应用长期变量: list := []*Demo{{"a"}, {"b"}} for _, v := range list { temp:=v go func() { fmt.Println("name="+temp.Name) }() }这样便可正确输入,其实从这种写法中也能看出问题的端倪。 在第一种没有应用长期变量时,主协程很快就运行结束,这时候打印的子协程可能还没运行;当开始运行的时候,这里的 v 曾经被最初一个赋值了。 所以这里打印的始终都是最初一个变量。 而应用长期变量会将以后遍历的值拷贝一份,天然就不会相互影响了。 当然除了长期变量也可应用闭包解决。 list := []*Demo{{"a"}, {"b"}} for _, v := range list { go func(temp *Demo) { fmt.Println("name="+temp.Name) }(v) }将参数通过闭包传递时,每个 goroutine 都会在本人的栈中寄存一份参数的拷贝,这样也能辨别了。 ...

December 28, 2021 · 2 min · jiezi

关于golang:Golang协程之了解管道的缓存能力

作者:ReganYue 起源:恒生LIGHT云社区 Golang协程之理解管道的缓存能力大家好,这里是致力变得优良的R君,这次咱们持续来进行Golang系列《让咱们一起Golang》,区块链系列内容明年会持续更新,共识算法曾经根本结束,如果不出意外,除夕那个星期就是介绍如何构建公链我的项目了,本次咱们来理解管道的缓存能力,这是一个比拟容易了解的知识点,咱们来看一看吧! 咱们之前讲过,当应用make建设管道时,第二个参数为零,就证实这个管道是无缓存能力的管道。只有没人写就永远读不进去,只有没人读就永远写不进去。例如: ch := make(chan int,0)管道的缓冲区能被初始化为指定的缓冲区容量。 如果为零,或者省略了大小,则该通道是无缓冲的。 如果将第二个参数改为8(这里能够为任意大小),这就阐明缓存能力为8,即便不读,也能写入8个元素。 package mainimport ( "fmt" "time")func main() { //The channel's buffer is initialized with the specified buffer capacity. //If zero, or the size is omitted, the channel is unbuffered. ch := make(chan int,0) go func() { ch <- 123 fmt.Println("数据已写入") }() go func() { time.Sleep(2*time.Second) x:= <- ch fmt.Println("数据已读出",x) }() time.Sleep(5*time.Second) fmt.Println("Game Over!")}这段代码在运行过程中,因为一条协程在写入管道缓冲区,另一条协程在读取管道的缓冲区,然而读取管道缓冲区的那条协程会sleep 两秒,所以在前两秒另一条写入管道缓冲区的协程也不能写入。 如果让写入管道缓冲区的那条协程sleep两秒,那么前两秒另一条读取管道缓冲区的协程也不能读取数据。 如果一个缓冲区大小为3的管道,写入4个值,那么第4个值就写入不了,运行后果是这样的: 写入1写入2写入3上面咱们来看一看管道内的元素个数及它的缓存能力吧: package mainimport ( "fmt" "time")func main101() { ch := make(chan int,3) go func() { ch <- 1 fmt.Println("写入1") ch <- 2 fmt.Println("写入2") ch <- 3 fmt.Println("写入3") //管道的缓冲区曾经存满,不能再写入! ch <- 4 fmt.Println("写入4") }() time.Sleep(5 * time.Second)}func main() { ch := make(chan int,3) fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch)); ch <- 123 fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch)); ch <- 123 fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch)); ch <- 123 fmt.Println("元素的个数为",len(ch),"缓存能力为",cap(ch)); }运行后果是 ...

December 28, 2021 · 1 min · jiezi

关于golang:Go-Quiz-从Go面试题看channel的注意事项

面试题这是Go Quiz系列的第2篇,对于channel和select的个性。 这道题比较简单,然而通过这道题能够加深咱们对channel和select的了解。 package mainfunc main() { c := make(chan int, 1) for done := false; !done; { select { default: print(1) done = true case <-c: print(2) c = nil case c <- 1: print(3) } }}A: 321B: 21C: 1D: 31这道题次要考查以下知识点: channel的数据收发在什么状况会阻塞?select的运行机制是怎么的?nil channel收发数据是什么后果?解析对于无缓冲区的channel,往channel发送数据和从channel接收数据都会阻塞。对于nil channel和有缓冲区的channel,收发数据的机制如下表所示: channelnil空的非空非满满了往channel发送数据阻塞发送胜利发送胜利阻塞从channel接收数据阻塞阻塞接管胜利接管胜利敞开channelpanic敞开胜利敞开胜利敞开胜利channel被敞开后: 往被敞开的channel发送数据会触发panic。从被敞开的channel接收数据,会先读完channel里的数据。如果数据读完了,持续从channel读数据会拿到channel里存储的元素类型的零值。channel被敞开后,如果再次敞开,会引发panic。select的运行机制如下: 选取一个可执行不阻塞的case分支,如果多个case分支都不阻塞,会随机算一个case分支执行,和case分支在代码里写的程序没关系。如果所有case分支都阻塞,会进入default分支执行。如果没有default分支,那select会阻塞,直到有一个case分支不阻塞。依据以上规定,本文最开始的题目,在运行的时候 第1次for循环,只有c <- 1是不阻塞的,所以最初一个case分支执行,打印3。第2次for循环,只有<-c是不阻塞的,所以第1个case分支执行,打印2,同时channel被赋值为nil。第3次for循环,因为channel是nil,对nil channel的读和写都阻塞,所以进入default分支,打印1,done设置为true,for循环退出,程序运行完结。因而打印后果是321,答案是A。 加餐:channel函数传参是援用传递?网上有些文章写Go的slice,map,channel作为函数参数是传援用,这是谬误的,Go语言里只有值传递,没有援用传递。 既然channel是值传递,那为什么channel作为函数形参时,函数外部对channel的读写对外部的实参channel是可见的呢? 对于这个问题,看Go的源码就高深莫测了。channel定义在src/runtime/chan.go第33行,源码地址:https://github.com/golang/go/... func makechan(t *chantype, size int) *hchan// channel构造体type hchan struct { qcount uint // total data in the queue dataqsiz uint // size of the circular queue buf unsafe.Pointer // points to an array of dataqsiz elements elemsize uint16 closed uint32 elemtype *_type // element type sendx uint // send index recvx uint // receive index recvq waitq // list of recv waiters sendq waitq // list of send waiters // lock protects all fields in hchan, as well as several // fields in sudogs blocked on this channel. // // Do not change another G's status while holding this lock // (in particular, do not ready a G), as this can deadlock // with stack shrinking. lock mutex}咱们通过make函数来创立channel时,Go会调用运行时的makechan函数。 ...

December 27, 2021 · 1 min · jiezi

关于golang:go图像验证码行为式验证码

go-captcha, 一个简洁易用、交互敌对、高安全性的点选行为验证码 Go 库 ,采纳 “验证码展现-采集用户行为-验证行为数据” 为流程,用户无需键盘手动输出,极大优化传统验证码用户体验不佳的问题,反对PC端及挪动端。 Github:https://github.com/wenlng/go-... Go实例代码:https://github.com/wenlng/go-... Vue实例代码:https://github.com/wenlng/go-... React实例代码:https://github.com/wenlng/go-... 在线演示:http://47.104.180.148:8081/go...

December 27, 2021 · 1 min · jiezi

关于golang:介绍一个-golang-图像验证码简单易用高安全性的行为式验证码Go库

go-captchago-captcha, 一个简洁易用、交互敌对、高安全性的点选行为验证码 Go 库 ,采纳 “验证码展现-采集用户行为-验证行为数据” 为流程,用户无需键盘手动输出,极大优化传统验证码用户体验不佳的问题,反对PC端及挪动端,带有与前端交互的DEMO。 Github:https://github.com/wenlng/go-captchaGo实例代码:https://github.com/wenlng/go-captcha-exampleVue实例代码:https://github.com/wenlng/go-captcha-example-vueReact实例代码:https://github.com/wenlng/go-captcha-example-react在线演示:http://47.104.180.148:8081/go_captcha_demo作者网站: http://witkeycode.com 中国Go模块代理GoProxy https://github.com/goproxy/go...AliProxy: https://mirrors.aliyun.com/go...OfficialProxy: https://goproxy.io/ChinaProxy:https://goproxy.cnOther:https://gocenter.io设置Go模块的代理Window $ set GO111MODULE=on$ set GOPROXY=https://goproxy.io,direct### The Golang 1.13+ can be executed directly$ go env -w GO111MODULE=on$ go env -w GOPROXY=https://goproxy.io,directLinux or Mac $ export GO111MODULE=on$ export GOPROXY=https://goproxy.io,direct### or$ echo "export GO111MODULE=on" >> ~/.profile$ echo "export GOPROXY=https://goproxy.cn,direct" >> ~/.profile$ source ~/.profile依赖golang官网规范库$ go get -u github.com/golang/freetype$ go get -u golang.org/x/crypto$ go get -u golang.org/x/image装置模块$ go get -u github.com/wenlng/go-captcha/captcha引入模块package mainimport "github.com/wenlng/go-captcha/captcha"func main(){ // ....}疾速应用package mainimport ( "fmt" "os" "github.com/wenlng/go-captcha/captcha")func main(){ // Captcha Single Instances capt := captcha.GetCaptcha() // 生成验证码 dots, b64, tb64, key, err := capt.Generate() if err != nil { panic(err) return } // 主图base64 fmt.Println(len(b64)) // 缩略图base64 fmt.Println(len(tb64)) // 惟一key fmt.Println(key) // 文本地位验证数据 fmt.Println(dots)}验证码实例创立实例或者获取单例模式的实例 ...

December 27, 2021 · 3 min · jiezi

关于golang:梦想总是要有的-工作20年程序员的2021年度总结

跌宕起伏的2021年快要过来了,往年对我来说经验的切实太多,提笔做个简略的总结吧。 回顾指标去年的年终总结,我给本人立了两个flag。 第一个尽管不可量化,不是一个好的指标,但我认为实现的还是不错的,go-zero 的工程效率曾经失去了社区的宽泛认可,感激所有应用和给咱们反馈的小伙伴们! 第二个指标,尽管很调侃的用了一个“小”字,我过后感觉是很难的,但幻想真的还是要有的,万一咱们实现了呢!正如我之前视频采访里说过的,人总要给本人制作一点艰难,毕竟艰难使人提高嘛。 这是 go-zero 开源一周年纪念日我发的朋友圈。 不平庸的 2021这一年,对教育行业、对团队、对我都是十分十分不容易的。感激好将来,尽管我来到了,但好将来的确是一个很不错的公司,期待它可能度过磨难,再次启航!感激晓黑板,我为之奋斗了四年,有彼此深深信赖的合伙人,有气味相投、危难时刻一起临阵脱逃的小伙伴。这真的是一段永生难忘的职业经验! 有太多的感激和不舍,但人总是要往前看的,但凡过往,皆为序章。 深度参加技术社区我本着开源精力,将好的技术和思考带给更多开发者,帮忙更多开发者晋升服务稳定性和开发效率,同时也进步技术认知,做了很多场深度技术分享,也给大家带来了一些技术人成长和思考的分享。 作为技术人,很多时候,咱们去听一场分享,总是心愿听到实实在在的技术干货,回去就能落到代码上,这真的是没错的,而且也是技术人的孜孜追求。但做了很多分享之后,我逐步发现,其实我分享的很多有深度的技术远没有我分享的那些技术理念和设计思维对大家的影响那么深远。 对我来说,分享一个有深度的技术是授人以鱼,分享一个好的技术理念是授人以渔。 可能对听众来说,预期是来听干货的,学到好的理念那算是额定的 bonus。 就技术干货分享来说,ArchSummit 这个分享反馈还是很不错的。 演讲视频:https://www.zhihu.com/zvideo/1398226082663809024 其实我做了更多对于技术理念的分享,其中之一就是讲我为啥给我的项目取 go-zero 这个名字,我心愿解决问题的时候是咱们回到原点去思考,而不是遇到钉子就找锤子。正所谓:做正确的事,正确的做事! 咱们在工作中遇到很多问题都是表象,如果你深究上来,或者这个问题自身就不存在,或者问题自身就是错的。比方最近跟老许(许式伟)做 Go+ 的时候,咱们去实现了本人的 packages.Load,须要去解决 package 屡次加载的缓存问题,为此写了很多代码,实现极其简单。最初老许发现其实咱们做的这些通过 Go 的一个命令就能解决,后果就是删除了上千行代码,效率晋升了近20倍,而且健壮性极大晋升。 老版本:ok github.com/goplus/gox 20.319s新版本:ok github.com/goplus/gox 1.142s最近马斯克带火了第一性原理,我的了解大体上就是:从基本登程,剔除烦扰因素和惯性思考。其实我感觉跟 go-zero 这个名字说的也是同一个情理。 再比方,我应字节技术学院邀请在字节做了个技术分享,分享完,大家对干货内容给了蛮好的评估,但过后根本就遗记了,或者落地完就完结了。但有个同学很久之后微信跟我说,过后分享到当初记得最粗浅、对他影响最大的是,过后有人问做前端的同学如果转做后端可行吗,我说:只有酷爱,前端能做好,后端肯定也能做好,技能是能够迁徙的,能力是相通的。我说这些是有事实根据的,我本人做过不少前端,团队有三个大牛后端程序员最早都是做挪动端的。这段送给前端想转后端又有所放心的同学,共勉! 开源停顿go-zero 收录于 CNCF 云原生技术全景图go-zero 被 CNCF Landscape 收录:https://landscape.cncf.io/?selected=go-zero 屡次登顶 GitHub Go 语言趋势榜,海内用户冀望咱们能用英文保护 issues 和 PR,他们也想参加社区,目前这事我还得想方法持续推动。 go-zero 一年万星后,我对其有两方面布局: 更多的投入到代码自身,让 go-zero 更简略易用,开发效率更高增强生态建设,联动微服务链路上下游顶级我的项目共建生态冀望大家多多关注、应用 go-zero,并让咱们听到你的声音(star, issue, PR),也能够退出 go-zero 社区,~7000人的社区能够帮你解决的不只是 go-zero 的应用问题。 ...

December 27, 2021 · 1 min · jiezi

关于golang:Go-Quiz-从Go面试题看slice的底层原理和注意事项

面试题最近Go 101的作者公布了11道Go面试题,十分乏味,打算写一个系列对每道题做具体解析。欢送大家关注。 大家能够看上面这道对于slice的题目,通过这道题咱们能够对slice的个性和注意事项有一个深刻了解。 package mainimport "fmt"func main() { a := [...]int{0, 1, 2, 3} x := a[:1] y := a[2:] x = append(x, y...) x = append(x, y...) fmt.Println(a, x)}A: [0 1 2 3] [0 2 3 3 3]B: [0 2 3 3] [0 2 3 3 3]C: [0 1 2 3] [0 2 3 2 3]D: [0 2 3 3] [0 2 3 2 3]大家能够在评论区留下你们的答案。这道题有几个考点: slice的底层数据结构是什么?给slice赋值,到底赋了什么内容?通过:操作失去的新slice和原slice是什么关系?新slice的长度和容量是多少?append在背地到底做了哪些事件?slice的扩容机制是什么?解析咱们先一一解答下面的问题。 slice的底层数据结构talk is cheap, show me the code. 间接上slice的源码: ...

December 26, 2021 · 4 min · jiezi

关于golang:Go标准库源码阅读之-io

io 规范库中外围是要了解 io.Reader 和 io.Writer 两个接口 // Reader 其实就是封装了下Read函数// Read函数冀望读取 len(p) bytes到 p 中,并返回理论读取的长度,即便数据有余 len(p) // 也会立刻返回;只有读取到的数据长度大于0,就要返回 err = nil; 如果没有可读取的数据,则返回 0, EOF; Read不容许呈现 0,nil 这样的返回值type Reader interface { Read(p []byte) (n int, err error)}// Reader 其实是封装了下Writer函数// Write 就是将 p 中保留的数据写入到内部结构体,并返回理论写入的数据// 同Read一样,返回值不能是 0, nil; 并且Write函数中不能扭转原始数据,哪怕长期扭转也不容许type Writer interface { Write(p []byte) (n int, err error)}围绕io.Reader/Writer,有几个罕用的实现: net.Conn, os.Stdin, os.File: 网络、规范输入输出、文件的流读取strings.Reader: 把字符串形象成Readerbytes.Reader: 把[]byte形象成Readerbytes.Buffer: 把[]byte形象成Reader和Writerbufio.Reader/Writer: 形象成带缓冲的流读取(比方按行读写)以 strings.Reader 源码举例剖析: // 当然 string.Reader 不仅仅实现了io.Reader接口,还反对很多// A Reader implements the io.Reader, io.ReaderAt, io.ByteReader, io.ByteScanner,// io.RuneReader, io.RuneScanner, io.Seeker, and io.WriterTo interfaces by reading// from a string.// The zero value for Reader operates like a Reader of an empty string.type Reader struct { s string i int64 // 指向当初读取的地位 prevRune int // index of previous rune; or < 0}// Read implements the io.Reader interface.func (r *Reader) Read(b []byte) (n int, err error) { // 曾经读到字符串开端,间接返回 io.EOF if r.i >= int64(len(r.s)) { return 0, io.EOF } // 因为是依照byte读的,所以这个标记位无意义 r.prevRune = -1 // 读取数据 n = copy(b, r.s[r.i:]) // 挪动读取地位指针,向后偏移理论读取的量 r.i += int64(n) return}当很多io相干的操作,比方读写文件、读写网络数据等场景都实现了 Write、Read 接口,那么很多跨io的操作就能够无缝实现,比方将网络读取的数据间接写入文件 ...

December 26, 2021 · 2 min · jiezi

关于golang:彻底理解Golang-Slice

看完这篇文章,上面这些高频面试题你都会答了吧Go slice的底层实现原理Go array和slice的区别Go slice深拷贝和浅拷贝Go slice扩容机制是怎么的?为什么Go slice是非线程平安的?实现原理slice是无固定长度的数组,底层构造是一个构造体,蕴含如下3个属性 一个 slice 在 golang 中占用 24 个 bytes type slice struct { array unsafe.Pointer len int cap int }array : 蕴含了一个指向一个数组的指针,数据实际上存储在这个指针指向的数组上,占用 8 bytes len: 以后 slice 应用到的长度,占用8 bytes cap : 以后 slice 的容量,同时也是底层数组 array 的长度, 8 bytes slice并不是真正意义上的动静数组,而是一个援用类型。slice总是指向一个底层array,slice的申明也能够像 array一样,只是长度可变。golang中通过语法糖,使得咱们能够像申明array一样,主动创立slice构造体 依据索引地位取切片slice 元素值时,默认取值范畴是(0~len(slice)-1),个别输入slice时,通常是指 slice[0:len(slice)-1],依据下标就能够输入所指向底层数组中的值 次要个性援用类型golang 有三个罕用的高级类型slice、map、channel, 它们都是援用类型,当援用类型作为函数参数时,可能会批改原内容数据。 func sliceModify(s []int) { s[0] = 100}func sliceAppend(s []int) []int { s = append(s, 100) return s}func sliceAppendPtr(s *[]int) { *s = append(*s, 100) return}// 留神:Go语言中所有的传参都是值传递(传值),都是一个正本,一个拷贝。// 拷贝的内容是非援用类型(int、string、struct等这些),在函数中就无奈批改原内容数据;// 拷贝的内容是援用类型(interface、指针、map、slice、chan等这些),这样就能够批改原内容数据。func TestSliceFn(t *testing.T) { // 参数为援用类型slice:外层slice的len/cap不会扭转,指向的底层数组会扭转 s := []int{1, 1, 1} newS := sliceAppend(s) // 函数内产生了扩容 t.Log(s, len(s), cap(s)) // [1 1 1] 3 3 t.Log(newS, len(newS), cap(newS)) // [1 1 1 100] 4 6 s2 := make([]int, 0, 5) newS = sliceAppend(s2) // 函数内未产生扩容 t.Log(s2, s2[0:5], len(s2), cap(s2)) // [] [100 0 0 0 0] 0 5 t.Log(newS, newS[0:5], len(newS), cap(newS)) // [100] [100 0 0 0 0] 1 5 // 参数为援用类型slice的指针:外层slice的len/cap会扭转,指向的底层数组会扭转 sliceAppendPtr(&s) t.Log(s, len(s), cap(s)) // [1 1 1 100] 4 6 sliceModify(s) t.Log(s, len(s), cap(s)) // [100 1 1 100] 4 6}公众号后盾caspar回复【代码】获取本文所有示例代码 ...

December 25, 2021 · 7 min · jiezi

关于golang:Go语言陷阱你可能想不到的字符串长度

在Go语言中,咱们要统计字符串中字符的个数,咱们必定会想到用utf8.RuneCountInString() 然而,这里咱们可能会碰到一个陷阱 咱们来看一段代码 func main() { data := "我" println(utf8.RuneCountInString(data)) data = "e" println(utf8.RuneCountInString(data))}在第3行代码中,输入后果是1,我置信大家都能想得到 在第6行代码中,你是否会感觉它会输入是1? 其实它的输入后果是 2 是不是感到很奇怪? 因为这是一个组合字符(Combining Diacritical Marks) e由两个字符组成别离是e和'https://stackoverflow.com/que...咱们肉眼看起来像是一个字符,其实它是由两个字符组成 e和é 这两个字符肉眼看起来仿佛是一样的 理论状况是前者蕴含了两个字符,后者只是一个字符 如果想解决这个问题,能够应用golang.org/x/text/unicode/norm这个包解决下字符https://www.unicode.org/repor... 以上就是本期内容 我是红豆,知易行难 咱们下期间见

December 24, 2021 · 1 min · jiezi

关于golang:一文读懂Go泛型设计和使用场景

前言2021.12.14日,Go官网正式公布了反对泛型的Go 1.18beta1版本,这是Go语言自2007年诞生以来,最重大的性能改革。 泛型外围就3个概念: Type parameters for functions and types 类型参数,能够用于泛型函数以及泛型类型 Type sets defined by interfaces Go 1.18之前,interface用来定义方法集( a set of methods)。 Go 1.18开始,还能够应用interface来定义类型集(a set of types),作为类型参数的Type constraint(类型限度) Type inference 类型推导,能够帮忙咱们在写代码的时候不必传递类型实参,由编译器自行推导。 留神:类型推导并不是永远都可行。 Type parameters(类型参数)[P, Q constraint1, R constraint2]这里定义了一个类型参数列表(type parameter list),列表里能够蕴含一个或者多个类型参数。 P,Q和R都是类型参数,contraint1和contraint2都是类型限度(type constraint)。 类型参数列表应用方括号[]类型参数倡议首字母大写,用来示意它们是类型先看一个简略示例: func min(x, y float64) float64 { if x < y { return x } return y}这个例子,只能计算2个float64中的较小者。有泛型之前,如果咱们要反对计算2个int或者其它数值类型的较小者,就须要实现新的函数、或者应用interface{},或者应用Refelect。 对于这个场景,应用泛型代码更简洁,效率也更优。反对比拟不同数值类型的泛型min函数实现如下: func min(T constraints.Ordered) (x, y T) T { if x < y { return x } return y}// 调用泛型函数m := min[int](2, 3)留神: ...

December 24, 2021 · 4 min · jiezi

关于golang:K8S-系列k8s-学习一Kubernetes-基本介绍及核心组件

Kubernetes 概述官网::https://kubernetes.io/ kubernetes github:https://github.com/kubernetes... 学习材料(语言能够自在切换):https://www.kubernetes.org.cn... kubernetes 有什么由来? 最开始是谷歌公司外部应用的 Borg 零碎,前面应用 Golang 重写并募捐给 CNCF 基金会开源了 kubernetes 重要的作用? kubernetes 是一个开源的容器编排框架工具,有着极其丰富的生态资源 学习 kubernetes 的意义? 解决单机裸跑 docker 的若干痛点 为什么 kubernetes 叫做 K8S ? 因为 k 到 s 之间 有 8个字母, 因而叫做 K8S kubernetes 有什么劣势?可主动装箱,可程度扩大,可自我修复有服务发现和负载平衡可集中化配置管理和秘钥治理可存储编排可工作批处理运行可主动公布和回滚 等等此处的主动公布默认是滚动公布模式 主动公布模式有如下 4 种: 蓝绿公布滚动公布 (kubernetes 默认公布形式)灰度公布金丝雀公布kubernetes 的四组概念Pod 和 Pod 控制器Pod 是 K8S 外面的概念, 是 K8S 外面可能被运行的最小逻辑单元,也就是原子单元 1 个 Pod 外面能够运行多个 docker 容器,多个 docker 容器是共享 UTS命名空间,NE命名空间T,IPC命名空间的 K8S 外面称这种 1 个 Pod 外面能够运行多个 docker 容器的模式叫做 边车模式(SideCar) ...

December 23, 2021 · 2 min · jiezi

关于golang:Go-modules基础精进六大核心概念全解析

一:模块门路 (Module Path)Go 应用 “module path” 来辨别不同的 module 模块,它在 go.mod 文件中被定义,这个文件中还蕴含了这个模块编译所需的其余依赖。如果一个目录中蕴含了 go.mod 文件,那么这个目录就是这个 Go 模块的根目录了。另外,还要介绍下包(package) 这个概念,它在 Go Modules 呈现之前就曾经存在了。Go 模块中的 “ 包 (package)” 是处于同一目录中的一些源代码文件的汇合,这些文件将被编译在一起。 “ 包门路(package path) ” 是模块门路和子目录(模块根目录的相对路径)的组合。举个例子,在模块 “golang.org/x/net” 下的 html 目录中有个包,这个包的门路是 “golang.org/x/net/html” 。总结下来就是: 一个代码仓库能够蕴含多个 Go 模块,一个 Go 模块能够蕴含多个 Go 包。模块门路是一个 Go 模块的标准名称,用于辨别不通的模块。同时他还是该模块下 Go 包的门路前缀。实践上,模块门路应该至多蕴含两个要害信息: 模块的作用 哪里获取该模块 二:版本号与兼容性准则版本号相当于是一个模块的只读快照,它能够是正式的发布版本,也能够是预公布版本。 每个版本都以字母 v 结尾,后跟一个语义版本,例如 v1.0.0。总而言之,语义版本由三个由点分隔的非负整数(次要版本、主要版本和补丁版本,从左到右)组成。 补丁版本后能够跟一个以连字符结尾的可选预公布字符串。 预公布字符串或补丁版本后能够跟一个以加号结尾的构建元数据字符串。 例如,v0.0.0、v1.12.134、v8.0.5-pre、v2.0.9+meta 等都是无效版本。版本号中的信息代表了这个版本是否是一个稳定版,是否放弃了与之前版本的兼容性。 当保护的模块产生了一些不兼容变更,比方批改了内部可调用的接口或者函数时,须要对主版本号进行递增,并且将次版本号和补丁版本号置为零。比方在模块中移除了一个包。在模块中增加一些新的函数或者接口,并没有影响模块的兼容性时,须要对次版本号进行递增,并且将补丁版本号置为零。当修复了一些 bug 或者进行了一些优化时,只须要对补丁版本号进行递增就能够了,因为这些变更不会对曾经公开的接口进行变更。预公布后缀代表了这个版本号是一个预公布版本。预公布版本号的排序会在正式版本号的后面。举个例子,v1.2.3-pre 会排列在 v1.2.3 后面。

December 23, 2021 · 1 min · jiezi

关于golang:step-1-搭建开发调试环境

装置dockerbrew cask install docker应用docker装置ubuntndocker pull ubuntu启动容器docker run --name=ubuntn --volume=~/WorkSpace:/root/workspace -d -it ubuntu:latest~/WorkSpace: 本人电脑上的工作目录/root/workspace:容器外面的工作目录查看容器iddocker ps | grep ubuntn进入容器docker exec -it ubuntn bash更新apt-get update -yapt-get upgrade -y装置软件apt-get install -y vim git curl git mercurial make binutils bison gcc build-essential配置gitgit config --global url."https://github.com.cnpmjs.org/".insteadOf "https://github.com/"次要解决应用https拉我的项目超时的问题。 配置容器vim ~/.bashrc在文件尾部追加 export LANG="en_US.UTF-8" # 设置零碎语言为 en_US.UTF-8,防止终端呈现中文乱码export PS1="[\u@dev \W]\$ " # 默认的 PS1 设置会展现全副的门路,为了避免过长,这里只展现:"用户名@dev 最初的目录名"export WORKSPACE="$HOME/workspace" # 设置工作目录,放go代码的地位export PATH="$PATH/bin:$PATH" # 将 $HOME/bin 目录退出到 PATH 变量中# Default entry foldercd $WORKSPACE # 登录零碎,默认进入 workspace 目录装置go版本管理工具gvmbash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)source /root/.gvm/scripts/gvm不便学习时候切换go版本做数据比照。 ...

December 23, 2021 · 1 min · jiezi

关于golang:Go-的-golangorgx-系列包和标准库包有什么区别

在开发过程中可能会遇到这样的状况,有一些包是引入自不同中央的,比方: golang.org/x/net/html 和 net/html,golang.org/x/crypto 和 crypto。那这是什么起因呢? 援用 Go 官网 Wiki 的说法: The golang.org/x/... repositories are part of the Go Project but outside the main Go tree. They are developed under looser compatibility requirements than the Go core. In general, they will support the previous two releases and tip. 大略意思就是,Go 规范库的包对向前兼容性有严格的规范。尽管 golang.org/x/... 系列包也是 Go 我的项目的一部分,然而在比 Go 规范库包更宽松的兼容性规范下开发,个别它们反对向前兼容两个版本。 golang.org/x/... 为官网的辅助包,是一种具备官网试验性质的包, 也就是说不排除有 BUG, 或者可能健壮性不是特地好;正式的规范库是有保障的包,前者有些成熟的性能会缓缓的放到规范库包里。 激情举荐: 技术博客: 硬核后端技术干货,内容包含 Python、Django、Docker、Go、Redis、ElasticSearch、Kafka、Linux 等。Go 程序员: Go 学习路线图,包含根底专栏,进阶专栏,源码浏览,实战开发,面试刷题,必读书单等一系列资源。面试题汇总: 包含 Python、Go、Redis、MySQL、Kafka、数据结构、算法、编程、网络等各种常考题。参考: ...

December 23, 2021 · 1 min · jiezi

关于golang:Go学习笔记汇编

前言本文是笔者学习Go汇编基础知识的笔记。本文的次要内容都是借鉴文章Go汇编语言,笔者在原文根底上扩大了局部写的比拟简略的内容,删除了一些笔者本人没有了解的内容。笔者心愿读者敌人们浏览本文后,可能: 理解Go汇编呈现的背景、起因和作用;理解汇编、Go汇编和Go语言三者之间的关系,以及它们呈现的背景和起因;利用所学的Go汇编根本语法常识,看懂golang库中一些汇编代码,同时也能手工写一些简略的Go汇编代码;通过golang代码输入的Go汇编代码来学习golang语言的一些底层实现原理;不过笔者能力无限,本文中必然存在不少谬误或者脱漏之处,欢送读者敌人们给予批评和斧正。 Go汇编简介Go汇编语言中写道: Go语言中很多设计思维和工具都是传承自Plan9操作系统,Go汇编语言也是基于Plan9汇编演变而来。依据Rob Pike的介绍,大神Ken Thompson在1986年为Plan9零碎编写的C语言编译器输入的汇编伪代码就是Plan9汇编的前身。所谓的Plan9汇编语言只是便于以手工形式书写该C语言编译器输入的汇编伪代码而已。Go汇编继承自Plan9汇编,其绝对于常见的汇编语言一个很大的特点是:可跨平台的,可移植的,与具体的底层操作系统无关的。咱们在golang的库中,常常能看到*.s文件,这些都是汇编代码,咱们利用Go汇编,能够更加高效的操作计算机CPU和内存,因而这些*.s文件通常都是为了进步代码运行效率。Go汇编语法和常见的汇编语言语法相似,一些中央做了简化,例如Go汇编中设置了一些伪寄存器,不便开发者应用。 Go汇编入门汇编基本知识Go汇编语言中写道: 汇编语言其实是一种非常简单的编程语言,因为它面向的计算机模型就是非常简单的。让人感觉汇编语言难学次要有几个起因:不同类型的CPU都有本人的一套指令;即便是雷同的CPU,32位和64位的运行模式仍然会有差别;不同的汇编工具同样有本人特有的汇编指令;不同的操作系统和高级编程语言和底层汇编的调用标准并不相同。咱们要想学习Go汇编,首先须要理解汇编中很根底的两个常识: 寄存器内存模型咱们编写汇编代码过程中,始终贯通着这两个知识点,Go汇编也不例外,所以学习这些常识能够帮忙咱们更好的了解Go汇编。 寄存器CPU只能计算,不能存储数据,程序计算中须要的数据都存储专用的硬件设施中,包含寄存器,一级缓存,二级缓存,RAM内存,磁盘等;因为CPU计算速度很快,读取/存储数据就会成为计算性能的瓶颈,古代计算机应用很多不同个性的存储设备,放慢数据的I/O,尽量进步程序的计算速度,其中寄存器就是一种容量很小,然而数据I/O十分高的专用存储设备,CPU会利用存放机来存储程序中罕用的数据,例如循环中的变量。下图是计算机中的存储设备阐明:寄存器不依附地址辨别数据,而依附名称,每一个寄存器都有本人的名称,咱们通知 CPU 去具体的哪一个寄存器拿数据,这样的速度是最快的。有人比喻寄存器是 CPU 的零级缓存。寄存器是CPU中最重要的资源,每个要解决的内存数据原则上须要先放到寄存器中能力由CPU解决,同时寄存器中解决完的后果须要再存入内存。Tips: 下面的粗体字表明的准则,咱们简称为“寄存器很重要准则”,请记住这条准则,前面咱们在剖析汇编代码的时候,会反复强调这条准则 内存模型内存模型是一个比拟形象的概念,笔者并不能很好解释这个概念。笔者本人的了解是寄存器容量很小,程序运行所需的大部分数据还是要存储在其余内存中,因而咱们须要理解,程序运行过程中,CPU如何操作各种内存,内存又是如何调配来存储各种数据,特地是在多cpu,多线程的状况下,所以咱们人为的制订了一套协定来标准这些行为,笔者把这个协定了解成内存模型。上面笔者将展现一张X86-64(十分罕用的计算机架构,它是AMD公司于1999年设计的x86架构的64位拓展,向后兼容于16位及32位的x86架构,X86-64目前正式名称为AMD64;咱们前面的汇编代码都是基于X86-64架构)架构的体系结构图,图中咱们将略微具体解说下内存模型,以及上文提到的寄存器和一些汇编指令。1.咱们先来关注下图中最右边的Memory局部,其示意的就是内存模型 内存从text局部到stack局部是从低地址(low)到高地址(high)增长;text示意代码段,个别用于存储要执行的指令数据,能够了解成存储咱们要执行的程序的代码,代码段个别都是只读的;rodata和data都是数据段,个别用于存储全局数据,其中rodata示意只读数据(read only data);heap示意堆,个别用于存储动态数据,堆的空间比拟大,能够存储较大的数据,例如go中创立的构造体;很多具备垃圾回收(gc)的语言中,如java,go,堆中的数据都是gc扫描后被主动清理回收的;stack示意栈,个别用于存储函数调用中相干的数据,例如函数中的局部变量,栈的特点就是FIFO,函数调用开始的时候,数据入栈,函数调用完结后,数据出栈,栈空间发出;go中,函数的入参和返回值也是通过栈来存储;汇编语言入门教程中对于内存模型有比拟具体的阐明,读者敌人们能够自行查看。 2.而后咱们来看下两头Register局部,它是X86提供的寄存器。寄存器是CPU中最重要的资源,每个要解决的内存数据原则上须要先放到寄存器中能力由CPU解决,同时寄存器中解决完的后果须要再存入内存。X86中除了状态寄存器FLAGS和指令寄存器IP两个非凡的寄存器外,还有AX、BX、CX、DX、SI、DI、BP、SP几个通用寄存器。在X86-64中又减少了八个以R8-R15形式命名的通用寄存器。提前记住这些寄存器名字,前面的示例汇编代码中会波及到。 3.最初咱们看下左边的Instructions局部,它是X86的指令集。CPU是由指令和寄存器组成,指令是每个CPU内置的算法,指令解决的对象就是全副的寄存器和内存。咱们能够将每个指令看作是CPU内置规范库中提供的一个个函数,而后基于这些函数结构更简单的程序的过程就是用汇编语言编程的过程。指令集指令的具体含意,能够自行百度。 咱们参考汇编语言学习中的一个示例来展现一下汇编语言编程。这个例子是一个性能很简略的函数:两数相加,后果赋值给一个变量sum,即sum = 5 + 6。 .data ;此为数据区sum DWORD 0 ;定义名为sum的变量.code ;此为代码区main PROC mov eax,5 ;将数字5送入而eax寄存器 add eax,6 ;eax寄存器加6 mox sum,eax INVOKE ExitProcess,0 ;完结程序main ENDP略微解释一下: mov eax,5中eax就是上文提到的通用寄存器AX,X86-64指令集外面咱们能够不写后面的r;咱们看到代码中.data和.code别离示意数据区和代码区,验证了上文提到的X86-64内存模型中的text和data局部;程序实现的性能是sum = 5 + 6,然而咱们不能间接在sum的内存外面做5 + 6的计算,记住上文提到的寄存器的一条重要准则:每个要解决的内存数据原则上须要先放到寄存器中能力由CPU解决,同时寄存器中解决完的后果须要再存入内存。Go汇编语法本文不会全面的介绍Go汇编语法,笔者本人也不分明到底有多少汇编命令;咱们会介绍一些罕用的命令,帮忙咱们前面浏览和了解Go汇编代码。1.咱们首先会介绍下Go汇编的伪寄存器。Go汇编为了简化汇编代码的编写,引入了PC、FP、SP、SB四个伪寄存器。四个伪寄存器加其它的通用寄存器就是Go汇编语言对CPU的从新形象,该形象的构造也实用于其它非X86类型的体系结构。四个伪寄存器和X86/AMD64的内存和寄存器的互相关系如下图: FP: Frame pointer:伪FP寄存器对应函数的栈帧指针,个别用来拜访函数的参数和返回值;golang语言中,函数的参数和返回值,函数中的局部变量,函数中调用子函数的参数和返回值都是存储在栈中的,咱们把这一段栈内存称为栈帧(frame),伪FP寄存器对应栈帧的底部,然而伪FP只包含函数的参数和返回值这部分内存,其余局部由伪SP寄存器示意;留神golang中函数的返回值也是通过栈帧返回的,这也是golang函数能够有多个返回值的起因;PC: Program counter:指令计数器,用于分支和跳转,它是汇编的IP寄存器的别名;SB: Static base pointer:个别用于申明函数或者全局变量,对应代码区(text)内存段底部;SP: Stack pointer:指向以后栈帧的局部变量的开始地位,个别用来援用函数的局部变量,这里须要留神汇编中也有一个SP寄存器,它们的区别是:1.伪SP寄存器指向栈帧(不包含函数参数和返回值局部)的底部,真SP寄存器对应栈的顶部;所以伪SP寄存器个别用于寻址函数局部变量,真SP寄存器个别用于调用子函数时,寻址子函数的参数和返回值(前面会有具体示例演示);2.当须要辨别伪寄存器和真寄存器的时候只须要记住一点:伪寄存器个别须要一个标识符和偏移量为前缀,如果没有标识符前缀则是真寄存器。比方(SP)、+8(SP)没有标识符前缀为真SP寄存器,而a(SP)、b+8(SP)有标识符为前缀示意伪寄存器;2.Go汇编罕用语法上面咱们重点介绍几个Go汇编罕用语法,不便咱们后续浏览了解示例Go汇编代码。 常量Go汇编语言中常量以$美元符号为前缀。常量的类型有整数常量、浮点数常量、字符常量和字符串常量等几种类型。以下是几种类型常量的例子: $1 // 十进制$0xf4f8fcff // 十六进制$1.5 // 浮点数$'a' // 字符$"abcd" // 字符串DATA命令用于初始化包变量,DATA命令的语法如下:DATA symbol+offset(SB)/width, value其中symbol为变量在汇编语言中对应的标识符,offset是符号开始地址的偏移量,width是要初始化内存的宽度大小,value是要初始化的值。其中以后包中Go语言定义的符号symbol,在汇编代码中对应·symbol,其中·中点符号为一个非凡的unicode符号;DATA命令示例如下 ...

December 22, 2021 · 15 min · jiezi

关于golang:Go编译原理系列2词法分析语法分析基础

前言关注公众号:IT猿圈,后盾回复:Go编译原理系列1,可取得pdf版在前一篇编译原理的文章中,并没有介绍词法剖析是如何将源文件中的字符转换成一个个的词法单元,两头用到了哪些技术或工具。也没有具体的介绍语法分析阶段中的一些常见的文法及语法分析形式。所以,本文你能够理解到: 词法分析器是如何将咱们的源文件中的字符翻译成词法单元的(不确定有穷状态机&确定有穷状态机)有哪些常见的词法分析器?他们是如何工作的?上下文无关文法Go语言中的一些文法的规定形象语法树的生成语法分析的一些办法(自顶向下、自底向上) Tips:下边的内容可能会比拟形象,特地是语法分析根底局部波及到的文法以及解决文法的两种办法。然而我都会通过表格或者图的形式,将每一步都形容分明,置信您保持看完,肯定会有所播种 词法剖析根底Token在前一篇编译原理的文章中能够晓得,词法剖析的工作是从左往右逐字符扫描源程序内容,辨认出各个单词,确定单词的类型。将辨认出的单词转换成对立的机内示意———词法单元(token)模式 比方辨认出这些单词是关键字、标识符、常量、界线符、还是运算符等。因为在任何一门编程语言中,这些类型是能够枚举的,所以个别会给定义好,比方Go语言中用_Name来示意标识符,用_Operator来示意操作符 像_Name、_Operator就是咱们常说的Token,最终被编译的源文件中的内容,都会被词法分析器解析成这样的Token模式 那词法解析器是如何辨认出源文件中各个单词,并判断单词是关键字?还是运算符?还是界线符的?这就用到了确定有穷自动机 不确定有穷自动机 & 确定有穷自动机这里不具体介绍有穷自动机里边的字母表、句子、符号等形象的概念,次要弄明确它是怎么工作的即可,它的实现不是本文的重点,对有穷自动机感兴趣的能够看《编译原理》的第三章 有穷自动机分为两类,即不确定的有穷自动机(NFA)和确定的有穷自动机(DFA)。下边顺次介绍这两个有穷自动机是如何工作的 不确定有穷自动机(NFA)其实咱们用一门编程语言编写的代码,能够看做是一个长字符串,词法剖析过程要做的就是辨认出这个长字符串中,哪些是关键字、哪些是运算符、哪些是标识符等 如果让咱们来做这样一件事件,最容易想到的就是用正则表达式。其实词法分析器进行解析的过程,也是利用正则,通过正则将长字符串进行宰割,宰割进去的字符串(可能是标识符、可能是运算符等)去匹配到相应的token 假如说有一个正则表达式(a|b)*abb,而后给你一个字符串,判断这个字符串是否满足这个正则表达式? 如果你对回溯算法比拟相熟的话,咱们晓得它能够通过简略的回溯算法来实现。然而这里用到另一种办法来实现,就是不确定有穷自动机(NFA) 依据前边给的正则表达式,能够画出如下的有穷自动机: 红色圆中的数字示意的是状态 当在0这个状态的时候遇到字符a或者b,则状态迁徙到自身0这个状态遇到a也能够迁徙到状态11这个状态遇到b,则迁徙到状态22这个状态遇到b,则迁徙到状态3(3是最终状态)该状态机一共有四个状态,其中0、1、2这三个状态是一个单层的圆示意的,3这个状态是用两层的圆示意的。单层的圆示意的是状态机的中间状态,双层的圆示意的是状态机的最终状态。箭头和其上方的字符,示意的是每个状态遇到不同的输出,迁徙到另一个状态 你能够把以下几个字符串作为上边这个状态机的输出,看是否可能走到最终状态,如果能走到,阐明能够匹配,如果不能走到,阐明不能匹配 能够匹配:abb、aabb、babb、aababb不可匹配:a、ab、bb、acabb从上边能够看进去,NFA可能解决匹配源文件中字符串目标,这样看如同咱们只有针对标识符、关键字、常量等写出相应的正则表达式,而后通过自动机就能宰割出源文件中各个字符串,而后匹配相应的token 然而它有一个缺点,比方拿abb去上边的状态机去匹配,0状态遇到a可能还是0这个状态,0状态再遇到0,还是0这个状态,再遇到b还是0这个状态,这样它又不能匹配了,实际上abb是能满足(a|b)*abb这个正则表达式的。起因就是在0状态的时候遇到a,它转移的状态是不确定的,所以它叫不确定有穷自动机 为了解决上边的问题,就呈现了确定有穷自动机 确定有穷自动机(DFA)还是上边那个正则表达式:(a|b)*abb,画出它的有穷自动机就是下边这样 0这个状态遇到a,则迁徙到状态10这个状态遇到b,则还是迁徙到自身状态01这个状态遇到a,则还是迁徙到自身状态11这个状态遇到b,则迁徙到状态22这个状态遇到a,则迁徙到状态12这个状态遇到b,则迁徙到状态3(3是最终状态)3这个状态遇到a,则迁徙到1状态3这个状态遇到b,则迁徙到0状态0、1、2是中间状态,3是最终状态。与不确定有穷自动机的区别就是,它的每一个状态遇到的输出,都会有一个确定的状态迁徙。你能够用前边给的字符串来验证一下这个有穷自动机 这样通过DFA就能够解决咱们的问题。然而,如果这样的话,要对一个源文件进行词法剖析,咱们就须要写很多的正则表达式,并且须要手动的为每一个正则表达式写有穷状态机的实现 为了解决这个问题,就呈现了很多的词法解析器的工具,能让咱们防止手动的去实现一个有穷自动机,下边就简略介绍两个常见的词法解析器的工具 词法分词器re2c咱们能够编写合乎re2c规定的文件,而后通过re2c生成.c的文件,再去编译执行这个.c文件 如果你没有装置re2c,须要先装置一下(点击下载)。下载实现之后,装置过程 1. 解压:tar -zxvf re2c-1.1.1.tar.gz2. 进入解压进去的目录:cd re2c-1.1.13. ./configure4. make && make install下边就是编写一个re2c的源文件。假如我要辨认一个数字是二进制的还是八进制的还是十六进制的,看一下用re2c是如何编写的(re2c的源文件是.l的文件) #include <stdio.h> //头文件,后边用到的标注输入输出就用到了这个头文件里的办法enum num_t { ERR, BIN, OCT, DEC, HEX }; //定义了5个枚举值static num_t lex(const char *YYCURSOR) //返回值类型是num_t。下边函数看着只有一行代码,还有一堆正文,其实这一堆正文就是re2c的外围代码,!re2c是它的结尾{ const char *YYMARKER; /*!re2c re2c:define:YYCTYPE = char; re2c:yyfill:enable = 0; end = "\x00"; bin = '0b'[01]+; //这些都是正则表达式 oct = "0"[0-7]*; dec = [1-9][0-9]*; hex = '0x'[0-9a-fA-F]+; * { return ERR; } bin end { return BIN; } //如归以匹配的二进制模式结尾,并且以匹配的end模式结尾,就返回二进制的枚举值,其余同理 oct end { return OCT; } dec end { return DEC; } hex end { return HEX; } */}int main(int argc, char **argv) //获取参数并遍历,调用lex函数,依据它的返回值来进行switch,看它属于那种类型的数字{ for (int i = 1; i < argc; ++i) { switch(lex(argv[i])) { case ERR: printf("error\n");break; case BIN: printf("binary\n");break; case OCT: printf("octal\n");break; case DEC: printf("decimal\n");break; case HEX: printf("hexadecimal\n");break; } } return 0;}阐明:如果你将代码粘过来不能失常应用,尝试把我写的正文去掉 ...

December 21, 2021 · 5 min · jiezi

关于golang:动手实现一个localcache-欣赏优秀的开源设计

前言哈喽,大家好,我是asong。上篇文章:入手实现一个localcache - 设计篇 介绍了设计一个本地缓存要思考的点,有读者敌人反馈能够借鉴bigcache的存储设计,能够缩小GC压力,这个是我之前没有思考到的,这种开源的优良设计值得咱们学习,所以在入手之前我浏览了几个优质的本地缓存库,总结了一下各个开源库的优良设计,本文咱们就一起来看一下。高效的并发拜访本地缓存的简略实现能够应用map[string]interface{} + sync.RWMutex的组合,应用sync.RWMutex对读进行了优化,然而当并发量上来当前,还是变成了串行读,期待锁的goroutine就会block住。为了解决这个问题咱们能够进行分桶,每个桶应用一把锁,缩小竞争。分桶也能够了解为分片,每一个缓存对象都依据他的key做hash(key),而后在进行分片:hash(key)%N,N就是要分片的数量;现实状况下,每个申请都均匀落在各自分片上,根本无锁竞争。 分片的实现次要思考两个点: hash算法的抉择,哈希算法的抉择要具备如下几个特点: 哈希后果离散率高,也就是随机性高防止产生多余的内存调配,防止垃圾回收造成的压力哈希算法运算效率高分片的数量抉择,分片并不是越多越好,依据教训,咱们的分片数能够抉择N的2次幂,分片时为了提高效率还能够应用位运算代替取余。开源的本地缓存库中 bigcache、go-cache、freecache都实现了分片性能,bigcache的hash抉择的是fnv64a算法、go-cache的hash抉择的是djb2算法、freechache抉择的是xxhash算法。这三种算法都是非加密哈希算法,具体选哪个算法更好呢,须要综合思考下面那三点,先比照一下运行效率,雷同的字符串状况下,比照benchmark: func BenchmarkFnv64a(b *testing.B) { b.ResetTimer() for i:=0; i < b.N; i++{ fnv64aSum64("test") } b.StopTimer()}func BenchmarkXxxHash(b *testing.B) { b.ResetTimer() for i:=0; i < b.N; i++{ hashFunc([]byte("test")) } b.StopTimer()}func BenchmarkDjb2(b *testing.B) { b.ResetTimer() max := big.NewInt(0).SetUint64(uint64(math.MaxUint32)) rnd, err := rand.Int(rand.Reader, max) var seed uint32 if err != nil { b.Logf("occur err %s", err.Error()) seed = insecurerand.Uint32() }else { seed = uint32(rnd.Uint64()) } for i:=0; i < b.N; i++{ djb33(seed,"test") } b.StopTimer()}运行后果: ...

December 20, 2021 · 2 min · jiezi

关于golang:超细细说Zookeeper选举的一个案例下

作者:ReganYue 起源:恒生LIGHT云社区 超细!细说Zookeeper选举的一个案例明天咱们来带着大家实现用Zookeeper实现选举的案例,帮忙大家更好的学习Zookeeper。 六、判断是否连贯Zookeeperfunc (electionManager *ElectionManager) isConnected() bool { if electionManager.ZKClientConn == nil { return false } else if electionManager.ZKClientConn.State() != zk.StateConnected { return false } return true}在初始化Zookeeper连贯时须要判断是否连贯了Zookeeper,其实咱们能够看连贯是否为nil值来判断有没有连贯,如果想判断连贯是否有问题的话,咱们最好用连贯的State()办法,如果是zk.StateConnected,就示意连贯胜利了,如果是其余就示意连贯异样,上面列举连贯异样和胜利的值。 StateUnknown State = -1StateDisconnected State = 0StateConnecting State = 1StateAuthFailed State = 4StateConnectedReadOnly State = 5StateSaslAuthenticated State = 6StateExpired State = -112StateConnected = State(100)StateHasSession = State(101)能够看到,zk.StateConnected也就是100,所以这里可能能够将zk.StateConnected替换为100,我也不晓得是否可行,你能够试一试~ StateUnknown也就是-1示意状态是未知的,StateDisconnected也就是0示意状态是未连贯,其它我就不细说了。 七、选举的逻辑func (electionManager *ElectionManager) Run() { err := electionManager.electMaster() if err != nil { fmt.Println(err) } electionManager.watchMaster()}是不是很眼生,这就是main函数中开拓协程运行的货色——选举。 ...

December 20, 2021 · 2 min · jiezi

关于golang:开源Goravel一个功能完备具有良好扩展能力的-Golang-Web-应用程序框架致敬-Laravel

对于 GoravelGoravel 是一个性能齐备、具备良好扩大能力的 Web 应用程序框架。 作为一个起始脚手架帮忙 Golang 开发者疾速构建本人的利用。我的项目地址:https://github.com/goravel/go...欢送 star 与 issues :) 次要性能[x] 自定义配置[x] HTTP 服务[x] 数据库 ORM[x] 数据库迁徙[x] 日志[ ] 缓存[ ] 队列[ ] 任务调度[ ] 事件零碎[ ] 邮件文档在线文档: https://www.goravel.dev/cn 文档仓库: https://github.com/goravel/docs 感激框架参考了 Laravel 的设计思维; 外围性能应用出名的 Golang 组件, 包含但不限于: spf13/viper 、 gin-gonic/gin 、 sirupsen/logrus、 go-gorm/gorm ; 文档参考了 LearnKu 社区 的 Laravel 中文文档 ; 向他们致敬! 开源许可Goravel 框架是在 MIT 许可 下的开源软件。

December 20, 2021 · 1 min · jiezi

关于golang:用-Go-实现一个-LRU-cache

前言早在几年前写过对于 LRU cache 的文章:https://crossoverjie.top/2018/04/07/algorithm/LRU-cache/ 过后是用 Java 实现的,最近我在欠缺 ptg 时正好须要一个最近起码应用的数据结构来存储历史记录。 ptg: Performance testing tool (Go), 用 Go 实现的 gRPC 客户端调试工具。Go 官网库中并没有相干的实现,思考到程序的简洁就不打算依赖第三方库,本人写一个;自身复杂度也不高,没有几行代码。 配合这个数据结构,我便在 ptg 中实现了申请历史记录的性能: 将每次的申请记录存储到 lru cache 中,最近应用到的历史记录排在靠前,同时也能提供相干的搜寻性能;具体可见下图。 实现 实现原理没什么好说的,和 Java 的一样: 一个双向链表存储数据的程序一个 map 存储最终的数据当数据达到下限时移除链表尾部数据将应用到的 Node 挪动到链表的头结点尽管 Go 比拟简洁,但好消息是根本的双向链表构造还是具备的。 所以基于此便定义了一个 LruCache: 依据之前的剖析: size 存储缓存大小。链表存储数据程序。map 存储数据。lock 用于管制并发平安。 接下来重点是两个函数:写入、查问。 写入时判断是否达到容量下限,达到后删除尾部数据;否则就想数据写入头部。 而获取数据时,这会将查问到的结点挪动到头结点。 这些结点操作都由 List 封装好了的。 所以应用起来也比拟不便。 最终就是通过这个 LruCache 实现了上图的成果,想要理解更多细节的能够参考源码: https://github.com/crossoverJie/ptg/blob/main/gui/lru.go

December 20, 2021 · 1 min · jiezi

关于golang:程序员必备的5个自媒体工具

工欲善其事,必先利其器,经营公众号也不例外。对于咱们技术类公众号,常见的工具有上面这些。 壹伴公众号的编辑器十分不好用,饱受诟病。所以,市场上呈现了很多第三方编辑器,补救公众号这方面的有余。在这泛滥的编辑器里,我最喜爱的还是壹伴。 除了编辑性能,壹伴还有个十分弱小的性能,能够间接将公众号文章抓取到后盾,便于后续的进一步编辑。如果没有这个性能的话,你转载一篇文章里须要复制注释,复制摘要/题目/浏览原文,封面还不能间接获取,十分不不便。有了壹伴,效率会进步很多。 TyporaTypora是一款轻便简洁的 Markdown 编辑器,反对即时渲染技术,它的界面十分简洁,你就能够专一于内容的书写,而不用花太多的精力在格局的编排上,就不会太多分心,效率会更高。此时的我,正在应用 Typora 编写这篇文章。 mdnicehttp://www.mdnice.com mdnice 也是一款 markdown 渲染排版软件,但间接用它来编写文章不太不便。Typora写作 + mdnice排版几乎就是绝配。 所以,我通常是两个一起联合应用,在 Typora 里编写好文章之后,再放到 mdnice 里进行排版。 二十次幂http://www.ershicimi.com 二十次幂能够用来查看一个公众号的历史发文,也能够看对应的浏览量,十分直观。我常常用它来寻找一些优质的公众号文章,对于本人后续的原创或转载都十分有帮忙。 openwritehttps://openwrite.cn/ 咱们能够把本人的原创文章发到各个博客平台上引流,但如果手动操作的话,须要先登录,再编辑文章,再抉择标签,最初再公布。一两个平台还好,但平台一多的话,几乎要命! openwrte 就是为解决这个痛点而生。你只有用 markdown 写好一篇文章,而后就能够一键同步到各大博客平台。目前反对 CSDN/博客园/简书/掘金/B站/今日头条/知乎等等,并且也始终在适配新的平台。 本文由博客一文多发平台 OpenWrite 公布!

December 19, 2021 · 1 min · jiezi

关于golang:程序员编码给自己转账超-21-万元华为辟谣-20-万月薪-工资条Go-118-Beta-1-可用-思否周刊

40s 新闻速递Win10 商店上线摸鱼 App微软 Win10/11 新补丁再次封禁第三方工具:将强制跳转至 Edge 浏览器程序员编码主动给本人微信转账 553 笔 超 21 万元Android 13 曝光:辞别疯狂杀后盾苹果筹备可折叠 iPhone:可能要等到 2024 年华为造谣 20 万月薪 "工资条":漏洞百出Win11 爆改 “刷新” 性能 导致大量用户不满Facebook 花 6000 万美元购买 Meta 商标资产微软 Bing 搜寻在中国边疆敞开“搜寻主动倡议”,局部地区网站无法访问iOS15.2 正式版公布 “数字遗产”性能正式上线QEMU 6.2 公布Cilium 1.11 公布Boost 1.78.0 公布CentOS Stream 9 公布 现已可用Rust 1.57 正式公布 Go 1.18 Beta 1 可用,带有泛型行业资讯Win10 商店上线摸鱼 AppWin10 商店上线了一款名为《摸鱼》的 App,作者示意:在下载关上之后,这个 App 会让你的电脑进入一个假更新的画面,让他人认为你的电脑正在降级,这时候你就能够劳动一下,优雅地喝一杯咖啡。   微软 Win10/11 新补丁再次封禁第三方工具:将强制跳转至 Edge 浏览器微软在刚刚为 Win10/11 推送的 “星期二补丁” 中,再次封禁了批改默认浏览器的第三方工具。在此次更新补丁装置后,用户为 microsoft-edge:// 协定抉择的备用应用程序将被删除,这导致用户只能抉择 Edge 浏览器关上搜寻,天气等性能的链接。 ...

December 19, 2021 · 2 min · jiezi

关于golang:Go语法基础

典型的Go文件布局package子句任何import语句理论代码// 每个Go文件都以package子句结尾,示意文件中的所有其余代码都属于“main”包package main// Go文件简直总是有一个或多个import语句import "fmt"// 当程序运行时,首先运行“main”函数func main() { // 通过从“fmt”包调用“Println”函数来实现在终端上显示内容 fmt.Println("Hello, World!")}文件须要先引入其余包,而后能力应用其余包里蕴含的代码。调用函数调用函数,须要输出函数名,以及一对圆括号。 函数能够接管一个或多个参数,参数呈现在函数名前面的圆括号中,多个参数用逗号分隔。 字符串字符串是一系列字节,通常示意文本字符。 Go把双引号之间的文本视为字符串。 在字符串中,换行符、制表符和其余难以蕴含在程序代码中的字符能够用转义序列来示意:反斜杠后跟示意另一个字符的字符。\n 示意换行符\t 示意制表符\" 示意双引号\\ 示意反斜杠 fmt.Println("Hello, \nWorld!")Hello,World!fmt.Println("Hello, \tWorld!")Hello, World!fmt.Println("\"\"")""fmt.Println("\\")\符文Go的符文(rune)用于示意单个字符。 字符串字面量由双引号("")突围,rune字面量由单引号('')突围。 Go应用Unicode规范来存储rune,rune被保留为数字代码,而不是字符自身。 转义序列能够用在rune字面量中。 fmt.Println('a')97布尔值布尔值只能是两个值中的一个:true 或 false。 数字Go将整数和浮点数视为不同的类型,能够应用小数点来辨别整数和浮点数。 运算符算术运算符 赋值运算符 关系运算符 逻辑运算符 类型Go是动态类型,它在程序运行之前就晓得值的类型是什么,如果在谬误的地位应用了谬误的值类型,Go会给出一个谬误音讯。 能够通过reflect包的TypeOf函数查看类型: fmt.Println(reflect.TypeOf(3.1415))float64根本类型 类型长度默认值形容bool1false byte10unit8int,unit4,80默认整数类型,保留数字。32或64int8,unit810 int16,unit1620 int32,unit3240 int64,unit6480 float3240.0 float6480.0默认浮点数类型,保留带小数局部的数字。complex648 complex12816 rune40 unitptr4,80 string "" 申明变量Go中,变量是蕴含值的一块存储。 应用var关键字,后跟所需的名称以及变量将保留的值的类型。 变量申明规范格局: var 变量名 变量类型a. 后置变量类型b. 变量命名规定遵循驼峰命名法c. 申明变量后,零碎会主动赋予该类型零值d. 申明但未应用的变量会被视为谬误var quantity int// 能够一次申明批准类型的多个变量var length, width float64var name string初始化变量申明变量后,能够应用=(单等号)为它调配该类型的值 ...

December 19, 2021 · 1 min · jiezi

关于golang:官方教程Go泛型入门

前言本周Go官网重磅公布了Go 1.18 beta 1版本,正式反对泛型。作为Go语言诞生12年以来最大的性能改革,官网配套推出了一个十分粗疏的Go泛型入门基础教程,通俗易懂。 自己对Go官网教程在翻译的根底上做了一些表述上的优化,以飨读者。 教程内容这个教程次要介绍Go泛型的基础知识。通过泛型,你能够申明和应用泛型函数,在调用函数的时候,容许应用不同类型的参数作为函数实参。 在这个教程里,咱们先申明2个简略的非泛型函数,而后在一个泛型函数里实现这2个函数的逻辑。 接下来通过以下几个局部来进行解说: 为你的代码创立一个目录实现非泛型函数实现一个泛型函数来解决不同类型调用泛型函数的时候移除类型实参申明类型限度(type constraint)留神:对于Go的其它教程,大家能够参考https://go.dev/doc/tutorial/。 留神:大家能够应用Go playground的Go dev branch模式来编写和运行你的泛型代码,地址https://go.dev/play/?v=gotip。 筹备工作装置Go 1.18 Beta 1或者更新的版本。装置指引能够参考上面的介绍。有一个代码编辑工具。任何文本编辑器都能够。有一个命令行终端。Go能够运行在Linux,Mac上的任何命令行终端,也能够运行在Windows的PowerShell或者cmd之上。装置和应用beta版本这个教程须要应用Go 1.18 Beta 1版本了的泛型性能。应用如下步骤,装置beta版本 应用上面的命令装置beta版本 $ go install golang.org/dl/go1.18beta1@latest运行如下命令来下载更新 $ go1.18beta1 download应用beta版本的go命令,不要去应用release版本的go命令 你能够通过间接应用go1.18beta1命令或者给go1.18beta1起一个简略的别名 间接应用go1.18beta1命令 $ go1.18beta1 version给go1.18beta1命令起一个别名 $ alias go=go1.18beta1$ go version上面的教程都假如你曾经把go1.18beta1命令设置了别名go。 为你的代码创立一个目录首先创立一个目录用于寄存你写的代码。 关上一个命令行终端,切换到你的home目录 在Linux或者Mac上执行如下命令(Linux或者Mac上只须要执行cd就能够进入到home目录) cd在Windows上执行如下命令 C:\> cd %HOMEPATH%在命令行终端,创立一个名为generics的目录 $ mkdir generics$ cd generics创立一个go module 运行go mod init命令,来给你的我的项目设置module门路 $ go mod init example/generics留神:对于生产代码,你能够依据我的项目理论状况来指定module门路,如果想理解更多,能够参考https://go.dev/doc/modules/ma...。 接下来,咱们来应用map写一些简略的代码。 实现非泛型函数在这个步骤,你要实现2个函数,每个函数都是把map里<key, value>对应的所有value相加,返回总和。 你须要申明2个函数,因为你要解决2种不同类型的map,一个map存储的value是int64类型,一个map存储的value是float64类型。 代码实现关上你的代码编辑器,在generics目录创立文件main.go,你的代码将实现在这个文件里。进入main.go,在文件最结尾,写包申明 package main一个独立的可执行程序总是申明在package main里,这点和库不一样。 在包申明的上面,写如下代码 ...

December 18, 2021 · 3 min · jiezi

关于golang:Go-如何编写-ProtoBuf-插件二

前言上篇文章《Go - 如何编写 ProtoBuf 插件 (一) 》,分享了应用 proto3 的 自定义选项 能够实现插件的编写,说到基于 MethodOptions 和 ServiceOptions 选项去实现 method 和 service 自定义设置拦截器。 接上篇文章,持续分享。 定义插件// plugin/interceptor/options/interceptor.protosyntax = "proto3";package interceptor;option go_package = "./;interceptor/options";import "google/protobuf/descriptor.proto";extend google.protobuf.MethodOptions { optional MethodHandler method_handler = 63500;}extend google.protobuf.ServiceOptions { optional ServiceHandler service_handler = 63501;}message MethodHandler { optional string authorization = 1; // login token optional string whitelist = 2; // ip whitelist optional bool logger = 3; // logger }message ServiceHandler { optional string authorization = 1; // login token optional string whitelist = 2; // ip whitelist optional bool logger = 3; // logger}接下来依据 interceptor.proto 生成 interceptor.pb.go ...

December 18, 2021 · 2 min · jiezi

关于golang:Go-如何编写-ProtoBuf-插件-一

前言咱们要晓得 proto3 和 proto2 的语法,并不是齐全兼容的。 具体可查阅官网文档: OverviewLanguage Guide (proto2)Language Guide (proto3)如果上述链接无奈关上,能够拜访这个文档:Overview - 语雀 。 自定义选项在 proto3 中,常见的实现插件的形式是应用 自定义选项,也就是 extend 标签,其中反对的 extend Options 有: MethodOptionsServiceOptionsEnumOptionsEnumValueOptionsMessageOptionsFieldOptionsFileOptionsOneofOptionsExtensionRangeOptions具体写法可参考: import "google/protobuf/descriptor.proto";extend google.protobuf.MessageOptions { optional string my_option = 51234;}message MyMessage { option (my_option) = "Hello world!";}需要场景假如,咱们的需要场景是这样的: 咱们有很多的拦截器,其中不同的 service 可能会应用一个或多个拦截器,不同的 method 也可能会应用一个或多个拦截器,在 helloworld.proto 中 service Greeter{} 反对登录令牌验证rpc SayHello1() 反对 IP 白名单限度和记录日志rpc SayHello2() 反对禁止记录日志// helloworld.protoservice Greeter { rpc SayHello1 (HelloRequest) returns (HelloReply) {} rpc SayHello2 (HelloRequest) returns (HelloReply) {}}message HelloRequest { string name = 1;}message HelloReply { string message = 1;}咱们须要在 proto 文件中,定义出 service 应用了哪些拦截器?定义出 method 应用了哪些拦截器?这样 proto 文件就会更加语义化,更加清晰明确,当大家看到定义的文件时,对应用的拦截器高深莫测。 ...

December 18, 2021 · 1 min · jiezi

关于golang:超细细说Zookeeper选举的一个案例上

作者:ReganYue 起源:恒生LIGHT云社区 超细!细说Zookeeper选举的一个案例明天咱们来带着大家实现用Zookeeper实现选举的案例,帮忙大家更好的学习Zookeeper。 一、装置所需第三方库应用Go来对Zookeeper进行操作须要应用 go get github.com/samuel/go-zookeeper/zk。依据GitHub上无关它的形容它是一个Zookeeper客户端~ 当然当初它的最新仓库地址是 https://github.com/go-zookeeper/zk 你也能够下载这个仓库的第三方库。 二、定义配置信息和选举治理信息的构造体type ZookeeperConfig struct { Servers []string RootPath string MasterPath string}type ElectionManager struct { ZKClinet *zk.Conn ZkConfig *ZookeeperConfig IsMaster chan bool}配置信息就是蕴含zookeeper集群服务器地址,根门路以及它的Master节点门路。 选举治理信息包含zookeeper的连贯信息、zookeeper的配置信息、以及传递选举信息的管道。 三、程序主逻辑func main() { zkconfig := &ZookeeperConfig{ Servers: []string{"node01:2181", "node02:2181", "node03:2181"}, RootPath: "/test04", MasterPath: "/master", } isMasterChan := make(chan bool) electionManager := NewElectionManager(zkconfig, isMasterChan) go electionManager.Run() var isMaster bool for { select { case isMaster = <-isMasterChan: if isMaster { fmt.Println("实现具体的业务逻辑") } } }}这个zkconfig是填入咱们要应用的zookeeper集群配置信息,isMasterChan建设用于返回选取后果的信道,而后创立选举管理器,正如咱们平时的选举有选举委员会一样,zookeeper的选举也须要选举管理器。而后开拓协程来进行选举:go electionManager.Run(),除了每次启动集群时会选举主节点之外,还须要监督主节点,如果主节点出问题了,须要立即选举出一个新的主节点。上面的isMaster是判断是否是主节点,是通过信道的返回值来判断的。而后上面的for循环,就是一直从管道中读取选举后果,是否胜利,如果胜利示意集群能够失常运作了,就能够实现具体的业务逻辑了,如果没选举胜利就只能始终期待了。 ...

December 17, 2021 · 1 min · jiezi

关于golang:pytest自动化测试视频文档分享

视频https://www.bilibili.com/vide... 文档pytest入门pytest课程纲要pytest简介下载和应用pytestpytest测试包及目录布局pytest的应用和调用pytest断言assertpytest fixturepytest fixture简介pytest fixture的作用域pytest调用fixture的三种办法pytest fixture参数pytest mark应用pytest-mark进行分类应用pytest-mark进行参数化测试应用pytest-mark设置用例执行程序应用pytest-mark标记用例跳过或间接失败应用pytest-mark标记超时工夫pytest高级pytest setup teardownpytest配置文件pytest.inipytest参数化测试pytest-allure生成测试报告pytest日志和代码覆盖率pytest日志治理pytest代码覆盖率pytest插件失败重跑pytest-rerunfailures多重校验pytest-assume用例依赖pytest-dependency分布式测试pytest-xdist生成报告pytest-html

December 17, 2021 · 1 min · jiezi

关于golang:Git视频文档分享

视频https://www.bilibili.com/vide... 文档Git入门Git简介Git的装置和配置Git的四个工作区域Git文件的四种状态Git命令Git常用命令Git配置用户签名Git初始化本地库查看Git状态Git将代码增加到暂存区Git提交代码Git批改并提交代码Git我的项目版本切换Git分支Git分支简介Git分支常用命令Git合并分支解决Git合并分支抵触GithubGit团队合作GitHub创立近程库GitHub推送本地库GitHub拉取近程库GitHub克隆近程库GitHub团队内合作GitHub跨团队合作GitHub免密登录IDE集成Git配置Git疏忽文件IDEA集成Git初始化本地库IDEA集成Git切换版本IDEA集成Git创立和切换分支IDEA集成Git合并分支IDEA集成Git合并分支并解决抵触IDEA集成Github在IDEA中配置GitHub在IDEA中推送我的项目到GitHub在IDEA中从GitHub拉取我的项目克隆GitHub中的我的项目码云Gitee码云Gitee简介IDEA集成码云GiteeGitlabGitLab简介GitLab装置与初始化IDEA集成GitLab

December 17, 2021 · 1 min · jiezi

关于golang:Java视频文档分享

Java视频https://www.bilibili.com/vide... Java文档和java相干的几件事件java语言的前生今世Java的应用领域java的职业倒退布局java学习办法Windows下java开发环境搭建MacOS下java开发环境搭建Linux下java开发环境搭建第一个Java程序Java开发工具开发工具atom的应用开发工具Eclipse开发工具IntelliJ IDEA关键字和保留字Java标识符Java命名标准Java数据类型Java整型Java浮点型Java BigDecimalJava 布尔类型Java字符类型ASCII字符编码unicode编码Java转义字符Java类型转换java原码、反码和补码java进制转换java变量和常量Java算术运算java自增自减java赋值运算java比拟(关系)运算符Java逻辑运算符java移位运算符Java 三元运算符Java运算符优先级和联合性Java流程管制Java分支语句if elseJava分支实例switch语句switch 实例Java循环构造Java for循环Java while循环Java do while循环Java break continue关键字Java循环实例阶段项目组总结-酒店管理系统Java字符串简介字符串的不可变性Java字符串格式化java字符串的罕用办法StringBuffer和StringBuilderJava数组的基本概念Java数组的基本操作Java二维数组Java数组根本算法Java数组的查找算法排序算法简介冒泡排序(Bubble Sort)抉择排序(Selection Sort)插入排序(Insertion Sort)java希尔排序(Shell Sort)java归并排序(Merge Sort)java疾速排序(Quick Sort)java堆排序(Heap Sort)java计数排序(Counting Sort)java桶排序(Bucket Sort)java基数排序(Radix Sort)Arrays工具类java数组的增删查改Java面向对象简介Java类和对象Java属性Java实例变量Java局部变量Java动态变量Java办法Java类办法和实例办法Java办法的重载Java的值传递机制java this关键字java 构造方法java static 关键字java 单例设计模式java包(package)治理java访问控制Java类与类之间的关系java代码块Java属性赋值的先后顺序java final 关键字MVC设计模式面向对象阶段我的项目总结-多课图书管理系统Java继承简介Java继承的规定Java instanceof 关键字Java办法笼罩Java办法笼罩和办法重载的区别Java super关键字Java子类的实例化过程Java抽象类和形象办法Java模板办法java接口简介Java接口的特点java接口和抽象类Java外部类java多态java OCP设计准则java异样简介Java异样的分类和常见异样类java异样解决Java抛出异样Java自定义异样java线程与过程创立线程的三种办法start与run办法sleep办法yield办法线程优先级线程join办法interrupt办法守护线程线程的状态Wait/notifywait / notify notifyAll apiwait vs sleepwait notify应用模式LockSupport 工具类死锁死锁经典案例-哲学家就餐问题活锁饥饿Reentrantlock简介线程平安剖析竞态条件和临界区synchronizedsynchronized-2变量的线程平安剖析java汇合框架简介java汇合collection接口java 迭代器iteratorjava汇合List接口java汇合ArrayListJava汇合LinkedListjava汇合Set接口java汇合HashSetjava汇合TreeSetJava汇合Map接口TreeMapjava 泛型简介java泛型的定义和应用java泛型,泛型类型变量的限定java泛型的束缚和局限性java泛型通配符Java File类的应用Java IO简介Java IO FileReaderjava IO FileWriterjava io FileInputStream 文件字节输出流java io FileOutputStreamjava IO 缓冲流Java转换流Java规范输入输出流java InetAddressjava socket编程模型java UDPJava URLjava枚举类简介java枚举,创立枚举类java枚举,Enum类java注解简介java文档注解java注解的保留策略(RetentionPolicy)和元素类型(ElementType)java元注解java内置注解(根本注解)java自定义注解java注解,在反射中应用注解Java反射简介java反射 Class对象java反射 取得构造方法java反射取得成员变量java反射取得成员办法java反射封装类java反射利用

December 17, 2021 · 1 min · jiezi