关于golang:GoPython双语言混合开发

download:Go+Python双语言混合开发1. 运算相干x,y,z为某个数字;list为列表abs(x):求x的绝对值;divmod(x, y):商余,同时输入商和余数,divmod(10, 3) —> (3, 1);pow(x, y):幂运算,x**y;pow(x, y, z):幂余,(x**y)%z;round(x):四舍五入,不保留小数;round(x, d):四舍五入,保留d位小数;min(list):获取数字列表中的最小值;max(list):获取数字列表中的最大值;sum(list):获取数字列表中的总和;int(x):将x取整,摄取小数局部;float(x):将x变成浮点数,减少小数局部;complex(x):将x变成复数,减少虚数局部;2. Sring与数字string为某个字符串;num为某个数字;firstNum为第一个数字;lastNum为最初一个数字;step为步长;u为unicode编码字符;old为老的子串;new为新的子串;sep为分隔的子串规定;fillchar为填充的字符;chars为字符;字符串的操作方法: string.title():让每个单词的首字母都改成大写;string.lower():字符串全字符小写;string.upper():字符串全字符大写;string.replace(old, new):所有old的子串被new子串替换;string.center(num):依据宽度num将字符串居中;string.center(num, fillchar):依据宽度num将字符串居中,其余字符应用fillchar填充;string.rstrip():删去字符串开端的空白;string.lstrip():删去字符串结尾的空白;string.strip():同时删去字符串两端空白;string.strip(chars):删去字符串两边呈现的字符chars;new.join(string):在string变量中除最初元素外每个元素后减少一个new子串;字符串的获取性能: string.count('xxx'):获取xxx在string中呈现的次数;string.split():以空格为分隔符将字符串拆分成多个局部,并贮存在一个列表里;string.split(sep):返回列表,依据sep将字符串分隔;len(string):获取字符串的长度;chr(u):返回u编码的字符x;ord(x):获取x的Unicode编码;其余类型转字符串的办法: str(num):将数字num转换成字符串;hex(num):将数字num转成十六进制字符串;oct(num):将数字num转成八进制字符串;字符串切片(同列表切片): string[firstNum: lastNum: step]:依据步长对字符串切片;string[::-1]:倒转字符串;字符串的格式化: "{} {}".format("hello", "world"):不设置指定地位,按默认程序输入 hello world;"{1} {0} {1}".format("hello", "world"):设置指定地位,输入 world hello world;format函数传入对象:class AssignValue(object): def __init__(self, value): self.value = valuemy_value = AssignValue(6)print('value 为: {0.value}'.format(my_value)) # "0" 是可选的可见,其实并不是想要均匀散布,而只是想要在最大的极限状况下和内容有余的时候,元素之间的间距是可控的。一般来说,这个解决形式挺多的,用 margin 之类的也是能够解决,不过目前有一个兼容性并不是非常好的 gap 能完满解决这个问题。 .wrapper { display: flex;flex-wrap: wrap;gap: 1rem;}

December 16, 2021 · 1 min · jiezi

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

前言哈喽,大家好,我是asong。最近想入手写一个localcache练练手,工作这么久了,也看过很多共事实现的本地缓存,都各有千秋,本人平时也在思考如何实现一个高性能的本地缓存,接下来我将基于本人的了解实现一版本地缓存,欢送各位大佬们提出宝贵意见,我会依据意见不断完善的。 本篇次要介绍设计一个本地缓存都要思考什么点,后续为实现文章,欢送关注这个系列。 为什么要有本地缓存随着互联网的遍及,用户数和访问量越来越大,这就须要咱们的利用撑持更多的并发量,比方某宝的首页流量,大量的用户同时进入首页,对咱们的应用服务器和数据库服务器造成的计算也是微小的,自身数据库拜访就占用数据库连贯,导致网络开销微小,在面对如此高的并发量下,数据库就会面临瓶颈,这时就要思考加缓存,缓存就分为分布式缓存和本地缓存,大多数场景咱们应用分布式缓存就能够满足要求,分布式缓存访问速度也很快,然而数据须要跨网络传输,在面对首页这种高并发量级下,对性能要求是很高的,不能放过一点点的性能优化空间,这时咱们就能够抉择应用本地缓存来进步性能,本地缓存不须要跨网络传输,利用和cache都在同一个过程外部,疾速申请,实用于首页这种数据更新频率较低的业务场景。 综上所述,咱们往往应用本地缓存后的零碎架构是这样的: <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/95d91bee0d0a40998e971bacb7e44bbc~tplv-k3u1fbpfcp-zoom-1.image" style="zoom:67%;" /> 本地缓存尽管带来性能优化,不过也是有一些弊病的,缓存与应用程序耦合,多个应用程序无奈间接的共享缓存,各利用或集群的各节点都须要保护本人的独自缓存,对内存是一种节约,应用缓存的是咱们程序员本人,咱们要依据依据数据类型、业务场景来精确判断应用何种类型的缓存,如何应用这种缓存,以最小的老本最快的效率达到最优的目标。 思考:如何实现一个高性能本地缓存数据结构第一步咱们就要思考数据该怎么存储;数据的查找效率要高,首先咱们就想到了哈希表,哈希表的查找效率高,工夫复杂度为O(1),能够满足咱们的需要;确定是应用什么构造来存储,接下来咱们要思考以什么类型进行存储,因为不同的业务场景应用的数据类型不同,为了通用,在java中咱们能够应用泛型,Go语言中临时没有泛型,咱们能够应用interface类型来代替,把解析数据交给程序员本人来进行断言,加强了可扩展性,同时也减少一些危险。 总结: 数据结构:哈希表;key:string类型;value:interface类型;并发平安本地缓存的利用必定会面对并发读写的场景,这是就要思考并发平安的问题。因为咱们抉择的是哈希构造,Go语言中次要提供了两种哈希,一种是非线程平安的map,一种是线程平安的sync.map,为了不便咱们能够间接抉择sync.map,也能够思考应用map+sync.RWMutex组合形式本人实现保障线程平安,网上有人对这两种形式进行比拟,在读操作远多于写操作的时候,应用sync.map的性能是远高于map+sync.RWMutex的组合的。在本地缓存中读操作是远高于写操作的,然而咱们本地缓存不仅反对进行数据存储的时候要应用锁,进行过期革除等操作时也须要加锁,所以应用map+sync.RWMutex的形式更灵便,所以这里咱们抉择这种形式保障并发平安。 高性能并发拜访加锁能够保证数据的读写安全性,然而会减少锁竞争,本地缓存原本就是为了晋升性能而设计进去,不能让其成为性能瓶颈,所以咱们要对锁竞争进行优化。针对本地缓存的利用场景,咱们能够依据key进行分桶解决,缩小锁竞争。 咱们的key都是string类型,所以咱们能够应用djb2哈希算法把key打散进行分桶,而后在对每一个桶进行加锁,也就是锁细化,缩小竞争。 对象下限因为本地缓存是在内存中存储的,内存都是有限度的,咱们不可能有限存储,所以咱们能够指定缓存对象的数量,依据咱们具体的利用场景去预估这个上限值,默认咱们抉择缓存的数量为1024。 淘汰策略因为咱们会设置缓存对象的数量,当触发上限值时,能够应用淘汰策略淘汰掉,常见的缓存淘汰算法有: LFULFU(Least Frequently Used)即最近不罕用算法,依据数据的历史拜访频率来淘汰数据,这种算法核心思想认为最近应用频率低的数据,很大概率不会再应用,把应用频率最小的数据置换进来。 存在的问题: 某些数据在短时间内被高频拜访,在之后的很长一段时间不再被拜访,因为之前的拜访频率急剧减少,那么在之后不会在短时间内被淘汰,占据着队列前头的地位,会导致更频繁应用的块更容易被革除掉,刚进入的缓存新数据也可能会很快的被删除。 LRULRU(Least Recently User)即最近起码应用算法,依据数据的历史拜访记录来淘汰数据,这种算法核心思想认为最近应用的数据很大概率会再次应用,最近一段时间没有应用的数据,很大概率不会再次应用,把最长工夫未被拜访的数据置换进来 存在问题: 当某个客户端拜访了大量的历史数据时,可能会使缓存中的数据被历史数据替换,升高缓存命中率。 FIFOFIFO(First in First out)即先进先出算法,这种算法的核心思想是最近刚拜访的,未来拜访的可能性比拟大,先进入缓存的数据最先被淘汰掉。 存在的问题: 这种算法采纳相对偏心的形式进行数据置换,很容易产生缺页中断问题。 Two QueuesTwo Queues是FIFO + LRU的联合,其核心思想是当数据第一次拜访时,将数据缓存在FIFO队列中,当数据第二次被拜访时将数据从FIFO队列移到LRU队列外面,这两个队列依照本人的办法淘汰数据。 存在问题: 这种算法和LRU-2统一,适应性差,存在LRU中的数据须要大量的拜访才会将历史记录革除掉。 ARUARU(Adaptive Replacement Cache)即自适应缓存替换算法,是LFU和LRU算法的联合应用,其核心思想是依据被淘汰数据的拜访状况,而减少对应 LRU 还是 LFU 链表的大小,ARU次要蕴含了四个链表,LRU 和 LRU Ghost , LFU 和 LFU Ghost, Ghost 链表为对应淘汰的数据记录链表,不记录数据,只记录 ID 等信息。 当数据被拜访时退出LRU队列,如果该数据再次被拜访,则同时被放到 LFU 链表中;如果该数据在LRU队列中淘汰了,那么该数据进入LRU Ghost队列,如果之后该数据在之后被再次拜访了,就减少LRU队列的大小,同时缩减LFU队列的大小。 存在问题: 因为要保护四个队列,会占用更多的内存空间。 抉择每一种算法都有本人特色,联合咱们本地缓存应用的场景,抉择ARU算法来做缓存缓存淘汰策略是一个不错的抉择,能够动静调整 LRU 和 LFU 的大小,以适应以后最佳的缓存命中。 过期革除除了应用缓存淘汰策略革除数据外,还能够增加一个过期工夫做双重保障,防止不常常拜访的数据始终占用内存。能够有两种做法: ...

December 16, 2021 · 1 min · jiezi

关于golang:重磅博睿数据Go语言智能探针技术GoAgent国内首发

随着容器编排、微服务、云技术等在 IT 行业一直流行,2009年诞生于Google的Golang(Go 语言,简称 Go)越来越受到软件工程师的欢送和追捧,成为现在煊赫一时的后端编程语言。 近日,博睿数据正式公布反对Go语言的智能探针(Smart Agent)技术,助力企业实现对Go语言相干应用服务的全面可观测性的建设。 国内首发反对Go语言 依据2021年Go趋势报告显示,寰球范畴内有 110 万业余开发者抉择Go作为其次要开发语言。如果把以其余编程语言作为次要开发语言,同时也在应用Go的开发者计算在内,这一数字将高达270万,中国的Go语言开发者排名第一,寰球占比超过16%。 Go 语言可能反对并构建与微服务联合的外部工具、架构和后端服务也深受IT企业欢送,许IT架构工具由Go构建而成,例如大型的Kubernetes、Docker和Vault等。数据显示,有63%的具备统治力的云原生我的项目都是用Go构建。 因而,博睿数据在国内首发反对Go语言智能探针,对于晋升业务性能,助力企业数字化转型有着十分重要的意义。 SmartAgent探针技术集结支流编程语言 SmartAgent是博睿数据自研的自动化部署的一体化探针,在已反对JAVA,PHP,.net,Nodejs,.NET Core,Python的根底上,新增了对Go语言的反对。 传统GoAgent VS博睿数据GoAgent 传统GoAgent探针技术VS博睿数据GoAgent智能探针技术:易用性与可观测性的同步晋升。 相较而言,传统探针技术须要客户配合批改利用程序代码,危险不可控,须要客户从新编译程序集成探针,耦合度高。 不同于行业内传统探针技术,博睿数据GoAgent探针间接后盾装置即可,被动注入和嵌码,升高与客户程序耦合、无需二次批改代码、进步 GoAgent 技术易用性。无论是动静编译还是动态编译的代码,博睿数据Samrt Agent技术都能够在不进行任何批改的状况下进行服务级别和代码级别的分布式链路跟踪,实现业务的可观测性。 GoAgent探针反对六大性能,实现全链路追踪 一张图看懂博睿GoAgent探针六大性能反对 为企业晋升数字化体验提供翻新动能 随同着企业数字化转型的遍及,APM技术曾经成为企业数字化引擎和弱小的能源。博睿数据SmartAgent探针技术作为APM的外围能力,具备包含装置便捷、兼容性强、监控能力强、性能耗费低、故障定位剖析效率低等多种劣势。无需研发配合,自动识别各语言应用程序,可做到自动化全办法的追踪与剖析,包含零碎级代码和用户级代码,可出现每一个类、每一个办法的执行效率。全面展示性能群组间的拓扑调用关系及业务调用节点的衰弱性能。在业务节点故障场景中,帮忙相熟各个运维场景和要害业务的IT人员迅速定位问题节点,缩短故障复原工夫,晋升企业IT服务工作效率。 将来,博睿数据在APM畛域还将持续发力,强化新技术、推动IT智能运维行业倒退,为企业数字化转型提供翻新动能。

December 16, 2021 · 1 min · jiezi

关于golang:编译原理概览

前言Go编译原理系列文章,试图深刻的搞清楚Go文本文件(.go)被编译器编译的整个过程,也就是下边这十一个过程 关注公众号:IT猿圈,后盾回复:Go编译原理系列1,可取得pdf版图片起源:《Go语言底层原理分析》 本系列文章会先从编译原理的角度,分享一下编译一门高级语言通常有哪些阶段,以及各个阶段在做什么;而后切回到Go编译器编译Go文本文件的过程,看它的编译过程有哪些本人独特的中央;最初,因为笔者对PHP语言也比拟相熟,会大抵分享一下PHP代码的解析与执行过程,刚好它是一门解释型语言,能够和Go这种编译型语言做个比照 长文warning!!! 综上,这个系列文章会蕴含以下几个主题 编译原理概览词法剖析&语法分析基础知识Go编译过程-词法剖析Go编译过程-语法分析Go编译过程-形象语法树构建Go编译过程-类型查看Go编译过程-变量捕捉Go编译过程-函数内联Go编译过程-逃逸剖析Go编译过程-闭包重写Go编译过程-遍历函数Go编译过程-SSA生成Go编译过程-机器码生成PHP代码的解释与执行-词法&语法分析PHP代码的解释与执行-opcodePHP代码的解释与执行-Zend编译型语言和解释型语言比照总结为防止内容过于干燥,相干中央会尽量画图 传统编译器的编译阶段介绍咱们晓得一门高级语言编写的代码,能够被咱们本人看懂,然而计算机看不懂。因而,它首先须要被翻译成一种可能被计算机执行的模式。实现这项翻译工作的软件系统,统称为编译器(compiler) 而编译原理,其实介绍的就是设计和实现编译器的办法。编译器设计的原理和技术,还能够利用于编译器设计之外的很多畛域 最相熟的就比方PHP中会用到模板引擎实现界面设计与代码的拆散,模板引擎对模板进行编译,造成可执行的 PHP 代码。如果你理解编译技术,会更容易把握这些模板引擎,甚至写出更合乎畛域需要的模板引擎 还有像数据库软件、大数据平台,都会用到编译原理中的思维。所以,学习编译原理并不是为了写一个编译器,学习其它计算机根底的货色,也是雷同的情理 语言处理器这部分次要是分享编译器、解释器是什么?以及将源程序翻译成指标机器的代码,两头还可能波及哪些过程?以及这些过程都干了什么? 编译器编译器其实就是一个程序,宏观上说,它能够浏览某一种语言(源语言)编写的程序,并把该程序翻译成为一个等价的、用另一种语言(目标语言)编写的程序 留神:如果目标程序是一个可执行的机器语言程序,那么它就能够被用户调用,解决输出并产生输入 解释器解释器(interpreter)是另一种常见的语言处理器,它并不通过翻译的形式生成目标程序。从用户的角度看,解释器间接利用用户提供的输出,执行源程序中指定的操作。在把用户输出映射成输入的过程中,由一个编译器产生的机器语言目标程序,通常比解释器快很多。然而,解释器的错误诊断成果,通常比编译器更好,因为它一一逐句地执行程序 示例Java语言处理器联合了编译和解释过程。一个Java源程序首先被编译成一个称为字节码(bytecode)的两头示意模式。而后由一个虚拟机对失去的字节码加以解释执行。这样安顿的益处之一是在一台机器上编译失去的字节码能够在另一台机器上解释执行。通过网络就能够实现机器之间的迁徙 为了更快地实现输出到输入的解决,有些被称为即时(just in time)编译器的Java编译器,在运行两头程序处理输出的前一刻,首先把字节码翻译成为机器语言,而后再执行程序 除了编译器之外,创立一个可执行的目标程序,还须要一些其它的程序。比方一个源程序可能被宰割成多个模块,并存放在不同的文件中。把源文件聚合在一起的工作,通常由一个称为预处理器(preprocessor)的程序实现。预处理器的职责还负责把那些称为宏的缩写模式转换成源语言的语句(C、C++) 而后,将通过预处理的源程序作为输出传递给一个编译器。 编译器可能产生一个汇编语言程序作为其输入,因为汇编语言比拟容易输入和调试。而后,这个汇编语言程序由称为汇编器 (assembler)的程序进行解决,并生成可重定位的机器代码 汇编器生成的机器代码,在内存中寄存的起始地位不是固定的,代码中的所有地址,都是绝对于这个起始地位的绝对地址。起始地址+绝对地址 = 相对地址(对于什么是可重定位的机器代码能够参考这篇文章) 大型程序常常被分成多个局部进行编译,因而,可重定位的机器代码要和其余可重定位的指标文件以及库文件链接到一起,造成真正在机器上运行的代码。一个文件中的代码可能指向另一个文件中的地位,而链接器(linker)可能解决内部内存地址的问题(内部内存地址,是指,一个文件中的代码,可能会援用另外一个文件中的数据对象或过程,这些数据对象的地址或过程地址,绝对于以后文件来说,就是内部内存地址)。最初,加载器(loader)把所有的可执行指标文件放到内存中执行 一个编译器的构造这部分就是大抵分享编译器的编译过程有哪几步?以及每步在做的事件。这部分可能会偏实践,然而我会尽量的联合示例,不便了解。并且会在一些设计算法或者设计的中央,分享它们在日常工作中的一些场景 编译器构造概览下边这个示例参考:编译原理(哈工大) 编译器是如何将一个高级的语言程序,翻译成机器语言程序的?能够看一下咱们是如何人工的将英语翻译成汉语的 In the room, he broke a window with a hammer这句英语就能够了解成是源语言,汉语就是目标语言。咱们翻译的过程,大抵分为两步 通过剖析源语言来取得句子的语义过程,就是语义剖析。语义剖析通常是从划分句子成分开始,首先是抓住句子的外围谓语动词,因为谓语动词的意思晓得了,句子的一半意思就晓得了。上边这句的谓语动词就是broke(打),晓得打这个动作,咱们就会想晓得,是谁施行了打这个动作?谁是被打的对象?用什么打的?为什么打?打的后果如何等等 这些都能够通过剖析broke的上下文来取得。上边的句子中,broke采纳的是被动语态,所以它的主语he,就是动作的实事者,宾语window就是动作的受事者。反过来,如果broke采纳的是被动语态be broken,那它的主语he就是动作的受事者 with a hammer是补语,示意动作应用的工具,in a room是状语,示意动作产生的地点。这样,咱们就能够剖析出broke前后的这些名词性成分同谓语动词broke之间的语义关系(这其实就是咱们进行语义剖析的过程)。比方下图 图地方的节点,示意句子中形容的打这个动作,四周的四个节点,对应着句子中的实体,别离是:he、window、hammer、room。从两头的结点,到四周的四个节点,别离引出了四条边,边上的信息示意这些实体同外围谓语动词之间的一一对应关系,其中he是动作的实施者agent,window是动作的受事者object,hammer是动作采纳的工具tool,room是动作产生的地点location 针对这个图的意思,用汉语翻译就是:在房间里,他用锤子砸了一扇窗户。这样就实现了翻译的过程。上边的图,就是一种两头示意,它独立于具体的语言,也就是说,英语能够用这个图示意,汉语也能够用这个图示意,日语、法语、意大利语都能够。有了这个图,不论目标语言是什么,都能够用这个图来翻译。所以两头示意很重要,它起到桥梁的作用 依据上边的剖析能够晓得,要想进行语义剖析,首先要划分句子成分。咱们晓得,主语和宾语通常是由名词短语形成的,状语和补语通常由介词短语形成的,因而,要想划分句子成分,就须要辨认出句子中的各类短语,这一过程称为语法分析。要想辨认句子中的各类短语,就须要晓得词性 比如说一个冠词+一个名词,能够以形成一个名词短语,一个代词自身,也能够形成一个名词短语。因而,要想辨认句子中的各类短语,要害是要确定句子中各个单词的词性,这一过程就是词法剖析 综上,咱们就能够晓得,要翻译一个句子,首先须要进行词法剖析,才词法剖析的根底上进行语法分析,而后进行语义剖析,也就是说,具体的翻译步骤就是,首先进行词法剖析,剖析出句子中各个单词的词性 而后进行语法分析 而后是语义剖析,依据句子的构造剖析出各个短语在句子中充当什么成分,从而确定各个名词性成分,和外围谓语动词之间的语义关系 最初失去两头示意模式 编译器的编译过程,也是经验了以上几个阶段 ...

December 16, 2021 · 3 min · jiezi

关于golang:goplaygroundvalidatorv10-自定义错误内容

当咱们援用了go-playground/validator/v10库并且配置了如下内容并配置了中文: Name string `json:"name" validate:"required"那么他的返回信息如下: Name为必填字段仍然不是很敌对,这个时候咱们就须要自定义谬误内容: 名称为必填字段代码如下: package utilsimport ( CN_ZH "github.com/go-playground/locales/zh" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" zhTranslations "github.com/go-playground/validator/v10/translations/zh" "reflect")var Validate *validator.Validate// Validate/v10 全局验证器var trans ut.Translator// 初始化Validate/v10国际化func init() { zh := CN_ZH.New() uni := ut.New(zh, zh) trans, _ = uni.GetTranslator("zh") Validate = validator.New() //通过label标签返回自定义谬误内容 Validate.RegisterTagNameFunc(func(field reflect.StructField) string { label := field.Tag.Get("label") if label == "" { return field.Name } return label }) zhTranslations.RegisterDefaultTranslations(Validate, trans) //自定义required_if谬误内容 Validate.RegisterTranslation("required_if", trans, func(ut ut.Translator) error { return ut.Add("required_if", "{0}为必填字段!", false) // see universal-translator for details }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T("required_if", fe.Field()) return t })}// 测验并返回测验错误信息func Translate(err error) (errMsg string) { errs := err.(validator.ValidationErrors) for _, err := range errs { errMsg = err.Translate(trans) } return}struct配置如下: ...

December 16, 2021 · 1 min · jiezi

关于golang:go118泛型的例子

go1.18 DockerfileFROM golang:1.18beta1-bullseyeWORKDIR /go/src/appCMD echo "欢送smallForest"CMD /bin/bashgo1.18泛型代码package mainimport "fmt"// SumInts adds together the values of m.func SumInts(m map[string]int64) int64 { var s int64 for _, v := range m { s += v } return s}// SumFloats adds together the values of m.func SumFloats(m map[string]float64) float64 { var s float64 for _, v := range m { s += v } return s}// SumIntsOrFloats sums the values of map m. It supports both int64 and float64// as types for map values.func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {var s Vfor _, v := range m {s += v}return s}type Number interface { int64 | float64}// SumNumbers sums the values of map m. Its supports both integers// and floats as map values.func SumNumbers[K comparable, V Number](m map[K]V) V { var s V for _, v := range m { s += v } return s}func main() { // Initialize a map for the integer values ints := map[string]int64{ "first": 34, "second": 12, } // Initialize a map for the float values floats := map[string]float64{ "first": 35.98, "second": 26.99, } fmt.Printf("Non-Generic Sums: %v and %v\n", SumInts(ints), SumFloats(floats)) fmt.Printf("Generic Sums: %v and %v\n", SumIntsOrFloats[string, int64](ints), SumIntsOrFloats[string, float64](floats)) fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n", SumIntsOrFloats(ints), SumIntsOrFloats(floats)) fmt.Printf("Generic Sums with Constraint: %v and %v\n", SumNumbers(ints), SumNumbers(floats))}https://go.dev/doc/tutorial/g... ...

December 16, 2021 · 2 min · jiezi

关于golang:Golang-Web开发文档视频分享

文档golang web开发之HTTP协定 Restful格调编程 golang http规范库 golang规范库template golang httprouter Gin简介 Gin实现用户登录 Gin申请参数 Gin 表单解决 Gin数据绑定 Gin拜访动态文件集成BootStrap框架 Gin应用中间件 应用Gin BasicAuth中间件 Gin cookie的应用 Gin 应用Session Gin 实现restful格调的CRUD Gin 实现路由分组 Gin 输入渲染 Gin实现文件上传 视频https://www.bilibili.com/vide...

December 15, 2021 · 1 min · jiezi

关于golang:重磅支持泛型的Go-118-Beta-1版本发布

前言2021年12月14日,Go官网公布了Go 1.18 Beta 1版本。 Go团队负责人Russ Cox在官网博客针对该版本公布做了具体阐明。 自己针对Russ的原文做了一个翻译,以飨读者。 原文翻译谷歌Go团队Russ Cox 2021.12.14 咱们刚刚公布了Go 1.18 Beta 1版本,大家能够从Downloads - go.dev进行下载。 官网正式的1.18版本还须要几个月才会对外公布。这是Go 1.18版本的第一个Beta版本,让大家能够提前感触新版本的性能,如果大家在应用过程中遇到了任何问题,也欢送提出来。 Go 1.18 Beta 1版本凝聚了谷歌的整个Go团队以及来自世界的Go语言贡献者的大量心血和付出,咱们十分期待听到大家对新版本的反馈。 Go 1.18 Beta 1版本是第一个反对泛型的Go预览版本(preview release)。泛型是Go 1.0版本公布以来Go语言做出的最重要的改革,也是咱们团队对繁多语言做过的最大改革。对于任何重大的新性能上线,让用户试用并发现bug是通用常规,泛型也不例外,大家能够先提前尝鲜,审慎应用。 此外,对于一些非凡场景,比方递归泛型的特定品种反对会延后在将来的版本公布。咱们晓得有一些晚期泛型使用者对于泛型应用得很欢快,如果你有一些场景认为适宜应用泛型,咱们也心愿你能够尝试下这个beta版本。咱们公布了一个对于泛型的简要教程,链接地址:Tutorial: Getting started with generics - go.dev,咱们也在上周的GopherCon会议上做了相干技术分享,链接地址:https://www.youtube.com/watch...。你也能够在Go Playground的Go dev模式下试用泛型,链接地址:Go Playground - go.dev。 Go 1.18 Beta 1增加了对于含糊测试(fuzzing-based tests)的内置反对,用于主动查找可能导致程序解体或者返回非法值的歹意输出。 Go 1.18 Beta 1新增了一个Go工作区模式(Go workspace mode),让你能够同时应用多个Go模块,这对于大型项目而言十分有用。 Go 1.18 Beta 1扩大了go version -m命令,这个命令会记录编译详细信息,比方编译标记。程序能够应用debug.ReadBuildInfo来查问本人的编译详细信息,还能够应用debug/buildinfo包来读取其它二进制文件的编译详细信息。这个性能是为了给帮忙Go二进制文件生成软件资料清单(software bill of materials, SBOM)的所有工具提供底层反对。 在往年早些时候,Go 1.17新增了基于寄存器的调用约定,用于减速Go代码在x86-64机器上的运行速度。Go 1.18 Beta 1扩大了这项性能到ARM64和PPC64架构上,会带来大略20%的速度晋升。 感激为这个Beta版本做出奉献的所有人,特别感谢谷歌的Go团队,大家为了让泛型在Go里实现,多年来始终不知疲倦地工作。咱们走过了漫长的一段路,咱们对目前的后果很称心,也心愿大家可能喜爱。 大家能够通过https://go.dev/tip/doc/go1.18查看Go 1.18 Beta 1版本的全副变更内容。 ...

December 15, 2021 · 1 min · jiezi

关于golang:使用-RESTful-API-去实现-beancount-记账

介绍一个我最近在保护的开源我的项目。 beancount 是一个十分优良的复试记账工具,但因为其基于文本以及丰盛的自由度,导致用户群体大多集中于极客群体,对个别的用户十分不敌对。相关联的可视化我的项目 fava ,肯定水平上简化了上手难度。然而 fava 在应用过程中,对于不太理解复式记账和 beancount 语法的新用户,仍然谈不上简略,而且 fava 也未能解决 beancount 在挪动端应用的问题。 beancount-gs 为 beancount 的应用提供了一套 RESTful API 的计划,基本原理是通过 bean-query 执行 bql 获取文本数据后,解析为 JSON 并返回。在应用上更偏差于日常流水账的记录形式,在保留灵活性的同时,使得新用户更容易上手应用。 已实现的性能: 多账本公有部署资产治理标签统计图表第三方账单导入(支付宝,微信领取)你可已拜访 Demo 进行体验。更具体的内能够在 beancount-gs 应用文档(更新中) 找到。 Github 地址

December 15, 2021 · 1 min · jiezi

关于golang:Go-为什么不支持可重入锁

大家好,我是煎鱼。 程序里的锁,是很多小伙伴在写分布式应用时用的最多的一个利器之一。 应用 Go 的同学里,绝大部分都有其余语言的教训,就会对其中一点有纳闷,那就是 Go 里的锁,居然不反对可重入? 为此,明天煎鱼带大家一起来理解这里的设计考量,看看为什么。 可重入锁如果对曾经上锁的一般互斥锁进行 “加锁” 操作,其后果要么失败,要么会阻塞至解锁。 锁的场景如下: 在加锁上:如果是可重入互斥锁,以后尝试加锁的线程如果就是持有该锁的线程时,加锁操作就会胜利。在解锁上:可重入互斥锁个别都会记录被加锁的次数,只有执行雷同次数的解锁操作才会真正解锁。简略来讲,可重入互斥锁是互斥锁的一种,同一线程对其屡次加锁不会产生死锁,又或是导致阻塞。 不同语言间实现可能或多或少有些区别,但大体意思差不多。 请你想一下,Go 是怎么样的呢? Go 反对状况咱们看到以下这个 Go 互斥锁例子: var mu sync.Mutexfunc main() { mu.Lock() mu.Lock()}这段 Go 程序会阻塞吗?不会,会报以下谬误: fatal error: all goroutines are asleep - deadlock!Go 显然是不反对可重入互斥锁的。 官网回复Go 设计准则在工程中应用互斥的根本原因是:为了爱护不变量,也能够用于爱护内、内部的不变量。 基于此,Go 在互斥锁设计上会恪守这几个准则。如下: 在调用 mutex.Lock 办法时,要保障这些变量的不变性放弃,不会在后续的过程中被毁坏。在调用 mu.Unlock 办法时,要保障: 程序不再须要依赖那些不变量。如果程序在互斥锁加锁期间毁坏了它们,则须要确保曾经复原了它们。不反对的起因讲了 Go 本人的设计准则后,那为什么不反对可重入呢? 其实 Russ Cox 于 2010 年在《Experimenting with GO》就给出了回答,认为递归(又称:重入)互斥是个坏主意,这个设计并不好。 咱们能够联合官网的例子来了解。 如下: func F() { mu.Lock() ... do some stuff ... G() ... do some more stuff ... mu.Unlock()}func G() { mu.Lock() ... do some stuff ... mu.Unlock()}在上述代码中,咱们在 F 办法中调用 mu.Lock 办法加上了锁。如果反对可重入锁,接着就会进入到 G 办法中。 ...

December 15, 2021 · 1 min · jiezi

关于golang:用-Go-Redis-实现分布式锁

为什么须要分布式锁用户下单锁住 uid,避免反复下单。 库存扣减锁住库存,避免超卖。 余额扣减锁住账户,避免并发操作。分布式系统中共享同一个资源时往往须要分布式锁来保障变更资源一致性。 分布式锁须要具备个性排他性锁的根本个性,并且只能被第一个持有者持有。 防死锁高并发场景下临界资源一旦产生死锁十分难以排查,通常能够通过设置超时工夫到期主动开释锁来躲避。 可重入锁持有者反对可重入,避免锁持有者再次重入时锁被超时开释。 高性能高可用锁是代码运行的要害前置节点,一旦不可用则业务间接就报故障了。高并发场景下,高性能高可用是根本要求。 实现 Redis 锁应先把握哪些知识点set 命令SET key value [EX seconds] [PX milliseconds] [NX|XX]EX second :设置键的过期工夫为 second 秒。 SET key value EX second 成果等同于 SETEX key second value 。PX millisecond :设置键的过期工夫为 millisecond 毫秒。 SET key value PX millisecond 成果等同于 PSETEX key millisecond value 。NX :只在键不存在时,才对键进行设置操作。 SET key value NX 成果等同于 SETNX key value 。XX :只在键曾经存在时,才对键进行设置操作。Redis.lua 脚本应用 redis lua 脚本能将一系列命令操作封装成 pipline 实现整体操作的原子性。 go-zero 分布式锁 RedisLock 源码剖析core/stores/redis/redislock.go ...

December 15, 2021 · 3 min · jiezi

关于golang:新提案Go-泛型玩出花来了switch-type-登场

大家好,我是煎鱼。 后面写过好几篇 Go 泛型的语法、案例介绍,新的一手 Go 音讯。实际上,随着一些提案被承受,新的提案也逐步冒出。 这不,我发现有了泛型后,大家能够更进一步玩出花来了。看到了一个 ”新“ 提案《proposal: spec: generics: type switch on parametric types》,讲的就是减少泛型后的参数类型上的类型开关诉求。 跟着煎鱼一起把握新的 Go 常识吧! 新提案新的提案内容是心愿减少一个新的变种语句,容许在 switch 语句中应用泛型时,可能进一步便捷的束缚其类型参数。 例如: switch type T {case A1:case A2, A3: ...}也就是 switch-type 语句的 T 类型能够是一个泛型的类型参,case 所对应的的类型能够是任何类型,包含泛型的束缚类型。 假如类型 T 的类型有可能是以下: interface{ C A}能够借助泛型的近似元素来束缚: interface{ C A1 | A2 | ... | An }甚至还能够在 case 上有新的写法: case interface {~T}:在反对泛型后,switch 在 type 和 case 上会存在很多种可能性,须要进行具体的个性反对,这个提案就是为此呈现。 理论案例案例一:多类型元素type Stringish interface { string | fmt.Stringer}func Concat[S Stringish](x []S "S Stringish") string { switch type S { case string: ... case fmt.Stringer: ... } }类型 S 可能反对 string 和 fmt.Stringer 类型,case 配套对应实现。 ...

December 14, 2021 · 2 min · jiezi

关于golang:深扒Go-embed

本文首发于 IEG增长中台技术团队公众号。 起因上周部署一个新我的项目,我的项目的配置文件追随我的项目目录寄存,还未放到配置核心。构建镜像运行时,因为没有拷贝配置文件,我的项目编译后的二进制文件读不到配置,服务起不来。 这是很多Go开发者或多或少都会遇到的经典文件门路问题。 这时要么写个部署脚本,每次构建镜像,把配置文件跟编译后的二进制文件放在一起。 但这时我想到了Go embed,往年Go公布了1.16,1.17两个版本,其中1.16里边的Go embed及io/fs就解决了这个经典文件门路问题。 Go embed应用传统的文件读取代码,配置文件须要追随二进制文件公布: func main() { fPath := "conf/conf.ini" c, err := ioutil.ReadFile(fPath) if err != nil { log.Fatal(err) } fmt.Println(string(c))} 换成Go embed的形式,配置文件会编译进最终的二进制文件,公布不须要拷贝配置文件,只需注解申明一个embed配置和定义一个embed变量: //go:embed conf/conf.inivar f embed.FSfunc main() { fPath := "conf/conf.ini" data, err := f.ReadFile(fPath) if err != nil { log.Fatal(err) } fmt.Println(string(data))} 源码实现通过下面的例子,咱们能够发现这个Go embed是编译期的行为,而且还是以注解的形式嵌入,有点离奇。Go的注解,目前我能想到的只有两个,别离是go:generate跟go:build,后者还是1.17新推出的注解,这感觉是Go逐步Java化? 获取注解执行go build -n查看embed形式代码的编译过程,上面是整个过程的局部截图。Go编译的外围有三个命令:compile/buildid/link(不在截图中),在compile动作之前,咱们能够看到跟embed注解相干的内容就是红框内的embedcfg文件,这里会将注解前面的文件门路"conf/conf.ini"信息结构化写到embedcfg文件。 Go编译期间的代码根本都集中在src/cmd/compile/internal/gc目录下,咱们在Main函数里边先找到go:embed注解的获取,就是下面的embedcfg: 一顿readEmbedCfg操作把刚刚的文件Unmarshal成正经的embedCfg struct: embedcfg的应用embedcfg结构化之后,还是compile的Main函数,外面会调用一个initEmbed的办法查看embedcfg的文件信息,并读取该门路对应的文件,将文件内容读取进去,最终跟compile期间的其余所有内容写到一个两头文件_pkg_.a,检查和读取文件的要害子办法为下图的fileStringSym,这里能够看到咱们相熟的文件系统调用open跟stat。 Go embed背地的设计上文咱们大抵理解了go:embed这个注解的应用和实现,但为什么要弄一个这种货色呢?难道就是为了解决配置文件部署问题吗?当然不是,go:embed的呈现是为了引人一个全新的文件系统库io/fs。 网上冲浪理解到,Go的创始人之一--Rob Pike在2016年就弄了一个提案,1.16之前的os.File并不是个接口,文件系统设计不形象,只能用来示意系统文件。 而咱们都晓得世界上最好的文件系统形象就是Unix,Unix的设计哲学正是"一切都是文件"。事实上Rob Pike也曾是贝尔实验室(Bell Labs)的Unix团队和Plan 9操作系统打算的成员。 ...

December 14, 2021 · 1 min · jiezi

关于golang:Go语言学习查缺补漏ing-Day8

作者:ReganYue 起源:恒生LIGHT云社区 Go语言学习查缺补漏ing Day8零、前言因为笔者根底不牢,在应用Go语言的时候常常遇到很多摸不着头脑的问题,所以笔者下定决心好好对Go语言进行查漏补缺,本【Go语言查缺补漏ing】系列次要是帮忙老手Gopher更好的理解Go语言的易错点、重难点。心愿各位看官可能喜爱,点点赞、关注一下呗! 一、为什么map的value值是不可寻址的?解决办法?先来看上面这段代码: package mainimport "fmt"type Hello struct { x, y int}var m = map[string]Hello{ "hello": Hello{2, 3},}func main() { m["hello"].x = 4 fmt.Println(m["hello"].x)}运行下面这个程序会报错: # command-line-arguments.\demo.go:14:15: cannot assign to struct field m["hello"].x in map为什么呢?上面来进行具体阐明: 因为map是无奈进行寻址的,也就是说能够获取m["hello"].x的值,然而不能对其值进行批改。 究其原因,因为Go的map是通过散列表来实现的,说得更具体一点,就是通过数组和链表组合实现的。 并且Go的map也能够做到动静扩容,当进行扩容之后,map的value那块空间地址就会产生变动,所以无奈对map的value进行寻址。 然而留神,map与slice切片的扩容有些不同,map是援用类型,扩容后,value援用地址不会变动,所以map value元素不可寻址。而slice扩容后是生成一个新的底层数组。 有什么解决办法呢? 解决办法一:应用长期变量 package mainimport "fmt"type Hello struct { x, y int}var m = map[string]Hello{ "hello": Hello{2, 3},}func main() { tmp := m["hello"] tmp.x = 4 m["hello"] = tmp fmt.Println(m["hello"].x)}解决办法二:应用指针 ...

December 13, 2021 · 2 min · jiezi

关于golang:尝鲜Go-118中范型版本的map和slice

大家最近都关注到了Go 1.18会反对范型的音讯了吧。 作为Golang的内置类型,大家都期待map和slice反对范型后,能够简化很多的判断逻辑,比方Equal逻辑等等。 几天前,Go范型的规范库曾经提交了,且能够试用了: 大家也能够读一下对应的代码:https://cs.opensource.google/... 废话不多说,咱们看下如何尝试范型版本的map和slice吧! 如何应用Go 1.18?Golang 官网链接只有1.17版本的下载,那么咱们如何能力应用1.18版本的Golang呢? 网上翻了翻,有人提供了Golang 1.18版本的Docker镜像 seongwoohong/golang-nightly:1.18,而且保障保护到1.18版本正式公布: 那么咱们就能够用如下命令启动一个go1.18的编译环境了: $ docker run --rm -it -v $PWD:/root/go-generics seongwoohong/golang-nightly:1.18 sh# cd /root/go-generics/~/go-generics #尝试maps翻了下maps的代码和测试用例,用上面的代码演示下maps的性能: package mainimport ( "fmt" "strconv" "golang.org/x/exp/maps" // v0.0.0-20211129234152-8a230f1f7d7a)func main() { var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16} var m2 = map[string]string{"1": "2", "2": "4", "4": "8", "8": "16"} var m3 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"} // Keys 办法返回map的所有键 // 如果没有范型,那么对于每种map,都须要写Keys办法,当初只须要一个 fmt.Printf("m1 Keys:\t%#v\n", maps.Keys(m1)) fmt.Printf("m2 Kyes:\t%#v\n", maps.Keys(m2)) // Values 办法返回map的所有值 fmt.Printf("m1 Values:\t%#v\n", maps.Values(m1)) fmt.Printf("m2 Values:\t%#v\n", maps.Values(m2)) // 判断map是否相等 fmt.Println("m1==m1?\t", maps.Equal(m1, m1)) fmt.Println("m2==m2?\t", maps.Equal(m2, m2)) //fmt.Println(maps.Equal(m1, m2)) // map[int]int与map[string]string无奈比拟 // 判断map是否相等(手动指定判断逻辑) fmt.Println("m1==m3?\t", maps.EqualFunc(m1, m3, func(v1 int, v2 string) bool { return strconv.Itoa(v1) == v2 })) // 还有一些Clear、Clone、Copy、DeleteFunc,都是见名知义的函数}而后编译执行看看: ...

December 12, 2021 · 2 min · jiezi

关于golang:浅谈在线广告分配策略

来自公众号:Gopher指北在线广告,也称网络广告、互联网广告,顾名思义,指的是在线媒体上投放的广告。平时咱们在刷信息流、短视频、新闻和微博均能够看见它的影子。对于比拟大的广告平台,用户定向后依旧会有大量的广告能够下发,而从大量的广告中抉择适合的广告展示给用户就是本篇要探讨的主题——在线广告调配策略。 名词形容为了更好的了解本文,先提前做一些名词形容。 eCPM(Effective Cost Per Mille): 指的是每一千次展现能够取得的广告支出。此指标反映盈利能力,不代表实际收入。不同的广告主会抉择CPC、CPM等不同出价形式,因而广告调配时无奈以纯正的出价进行比拟,所以才有了ecpm这一指标用于评估不同出价形式的广告能够给广告平台带来的收益。 定向广告:所谓"定向"实际上是对受众的筛选,即广告的显示是依据访问者来决定的,先进的广告管理系统 可能提供多种多样的定向形式。 最好的肯定适合嘛对于广告平台而言收益最大化是优先事项。为了保障收益最大化,对于每一次广告申请咱们都抉择ecpm最高的广告下发。这个逻辑从实践上来看是正确的,但在理论中就不肯定了,那么它到底会有什么问题呢? ⼴告耗费超预算限额。广告估算耗费不尽。空后果问题。局部广告耗费过快影响广告主投放体验和用户产品体验。问题剖析问题1 对问题1进行剖析时,咱们须要先有这样一个共识,广告的点击、曝光等数据上报有肯定的延时。 因为广告调配策略未思考估算耗费信息,当耗费靠近估算限额时未能及时减缓曝光速度,导致本应调配给其余广告主的流量仍旧调配给了估算受限的广告主,这是对广告平台流量的节约(流量越大的平台节约会更加重大)。 问题2 局部中小广告主竞争力弱(出价低),很难获取足够的曝光量,这种情景当广告富余时尤为显著。 问题3 一方面可能是因为广告资源有余,另外一方面也有可能是定向广告耗费过快(详见上面的例子)。 问题4 广告依照ecpm排序,会导致广告耗费速度差别较大间接影响广告主的投放体验,甚至于用户重复看到反复的广告间接影响用户产品体验,再反过来影响到广告的CVR。 为了进一步阐明纯按价高者得这一算法的不足之处,请看上面的非凡例子。 广告出价($)估算($)定向A0.5100男,游戏B1100男,游戏,静止以上述广告为例,现有男,游戏和男,静止申请各100。现实最大收益为150$,然而依照上述策略调配广告时,会呈现男,游戏这100申请先达到时优先耗费B广告,男,静止`这100申请达到时无广告可耗费。依照ecpm排序的算法又称为Greedy算法,该算法会让高价值广告疾速耗费。 适合的才是最好的Balance算法与Greedy算法不同的是,Kalyanasundaram和Pruhs提出的Balance算法疏忽单个bidder的出价,尽可能均衡所有bidder的估算耗费,使得其在线工夫尽可能⻓,即尽量使得所有⼴告都放弃匀速投放。其算法形容如下: 当一个满足一些定向广告的申请达到时:if 广告估算耗费完 { continue} else { 抉择一个(耗费/估算)值最小的一个广告}相比贪婪算法,Balance算法均衡所有广告的耗费速度,可能无效解决贪婪算法广告疾速耗费的问题,但在广告耗费不尽的问题上仍旧不是最佳解决方案。咱们看上面非凡例子: 广告出价(&dollar;)估算(&dollar;)定向A1100男,游戏B0.01100男,游戏,静止以上述广告为例,现有男,游戏和男,静止申请各100。现实对最大收益为110$,依据balance算法其总的估算耗费仅为几美元。当男,游戏这100申请先达到时,B广告肯定会先耗费完,当男,静止`100申请达到时依旧会无广告可耗费。 那Balance算法实用场景到底是什么,上面咱们以极限法来思考这个问题。 假如一:如果广告A和广告B的出价别离为1000&dollar;和1&dollar;(CPC) 很显著,广告A具备更大的劣势理当优先展现。依据后面的例子,Balance算法是无奈解决这种极值场景的,而Greedy算法则充沛兼顾了平台的利益以及广告主急迫花钱的情绪。 假如二:如果所有广告出价别离为10&dollar;(CPC) Greedy算法是和出价无关的,而Balance算法仅和估算无关。依据控制变量法很容易晓得Balance算法正是为了这种场景而生。 小结:依据后面的假如以及论文中的形容咱们总结如下论断: Balance算法更实用于广告出价比拟靠近的场景Greedy算法则比拟实用于广告出价差别比拟大的场景MSVV算法只有小孩子才做选做题,咱们成年人全都要。Balance算法和Greedy算法各有优劣且实用场景不同,那有没有算法可能交融两者的长处呢?这正式MSVV算法的思路。 为了更分明形容新算法,先给出一些根本定义: 算法形容如下: 当一个满足一些定向广告的申请达到时:if 广告估算耗费完 { continue} else { 抉择一个`缩放出价`值最大的广告}上述的衡量函数为一个枯燥降落的函数,且\( v \)取值范畴为[0,1]。衡量函数分布图如下: 当所有广告出价相等时,因为衡量函数是一个枯燥降落的函数,因而MSVV算法就正好进化成Balance算法。另一方面,如果出价差别十分大时,MSVV算法在大多数状况都不会扭转出价的程序,此时MSVV体现更靠近Greedy算法。思考更极其的状况,当所有广告估算都是有限时,MSVV算法间接进化为Greedy算法,因为此时衡量函数为常量\( 1 - {\frac 1 e} \)。 为了验证MSVV算法的适应性,咱们看上面的代码: type ad struct { cost float64 total float64 price float64}func scaled(price, cost, total float64) float64 { return price * (1.0 - math.Pow(math.E, cost/total-1))}func main() { a := &ad{0, 100, 1} b := &ad{0, 100, 0.01} // 模仿`男,游戏`达到时,a和b同时耗费 for i := 0; i < 100; i++ { aCp := scaled(a.price, a.cost, a.total) bCp := scaled(b.price, b.cost, b.total) if a.cost >= a.total || b.cost >= b.total { break } if aCp >= bCp { a.cost += a.price } else { b.cost += b.price } } // 模仿`男,静止`达到时,仅b可耗费 for i := 0; i < 100; i++ { if b.cost >= b.total { break } b.cost += b.price } fmt.Println(a.cost + b.cost)}MSVV算法在后面的极值例子中收益别离为116.5和101,其整体体现根本合乎预期。 ...

December 12, 2021 · 1 min · jiezi

关于golang:一文读懂Go匿名结构体使用场景

前言匿名行为在go语言里十分常见,比方: 匿名函数:也就是咱们熟知的闭包(Closure)构造体里的匿名字段(Anonymous Fields)匿名构造体(Anonymous Structs)匿名行为的设计带来了一些了解上的艰难,然而相熟了匿名设计的应用后,你会发现匿名设计在某些特定场景能够帮忙大家写出更简洁、更优雅、更高效和更平安的代码。 什么是匿名构造体匿名构造体:顾名思义,就是构造体没有命名。比方上面的代码示例: // example1.gopackage mainimport ( "fmt")func main() { a := struct{name string; age int}{"bob", 10} b := struct{ school string city string }{"THU", "Beijing"} fmt.Println(a, b)}在这个例子里,咱们定义了2个变量a和b,它们都是匿名构造体变量。 常见的应用场景全局变量组合有时候咱们会在程序里定义若干全局变量,有些全局变量的含意是相互关联的,这个时候咱们能够应用匿名构造体把这些关联的全局变量组合在一起。 // example2.gopackage mainimport "fmt"// DBConfig 申明全局匿名构造体变量var DBConfig struct { user string pwd string host string port int db string}// SysConfig 全局匿名构造体变量也能够在申明的时候间接初始化赋值var SysConfig = struct{ sysName string mode string}{"tutorial", "debug"}func main() { // 给匿名构造体变量DBConfig赋值 DBConfig.user = "root" DBConfig.pwd = "root" DBConfig.host = "127.0.0.1" DBConfig.port = 3306 DBConfig.db = "test_db" fmt.Println(DBConfig)}对全局匿名构造体变量实现赋值后,后续代码都能够应用这个匿名构造体变量。 ...

December 11, 2021 · 2 min · jiezi

关于golang:Prometheus-快速入门02

数据模型Prometheus 底层将所有数据存储为工夫序列: 即以雷同 metric 和 label 维度聚合的带工夫戳的流。 时序格局上面格局示意一个 metric 和 label 的时序数据汇合 <metric name>{<label name>=<label value>, ...}例如,一个工夫序列的度量名称 api_http_requests_total 和 label 办法="POST" 和handler="/messages"能够写成这样: api_http_requests_total{method="POST", handler="/messages"}采样Prometheus 通过 pull 收到各个 metric 的理论数据,样本造成理论的工夫序列数据,每个样本包含: float64值一个毫秒精度工夫戳小结Prometheus 以 metric 和 label 的维度聚合时序数据Prometheus 以 pull 形式,收集各个监控指标上 metric 的值与工夫戳Metric 类型Prometheus Metric 有四种类型:Counter,Gauge,Histogram,Summary Counter个性:只增不减实用:服务申请数、已实现工作数、谬误呈现次数等示例:http 申请数# TYPE prometheus_http_requests_total counterprometheus_http_requests_total{code="200",handler="/-/ready"} 6prometheus_http_requests_total{code="200",handler="/api/v1/label/:name/values"} 43prometheus_http_requests_total{code="200",handler="/api/v1/labels"} 35Go SDK:// counter + 1Inc()// counter + 任意值,这个值小于 0, 则 panicAdd(float64)Gauge个性:数据能够任意变动,可增可减实用:温度、内存/磁盘使用率等示例:go 以后协程数# TYPE go_goroutines gaugego_goroutines 35Go SDK:// 设置任意值Set(float64)// 加一Inc()// 减1Dec()// 加任意值Add(float64)// 减任意值Sub(float64)// 设置成以后工夫的 unix 秒值SetToCurrentTime()Histogram(直方图)个性:一段时间范畴内对数据进行采样,对其指定区间以及总数进行统计实用:页面的响应工夫散布、resp 的 body 大小散布等...示例:http 申请延时# HELP prometheus_http_request_duration_seconds Histogram of latencies for HTTP requests.# TYPE prometheus_http_request_duration_seconds histogramprometheus_http_request_duration_seconds_bucket{handler="/",le="0.1"} 6 // 延时小于 0.1 s 的申请数 6 个prometheus_http_request_duration_seconds_bucket{handler="/",le="0.2"} 6 // 延时小于 0.2 s 的申请数 6 个prometheus_http_request_duration_seconds_bucket{handler="/",le="0.4"} 6prometheus_http_request_duration_seconds_bucket{handler="/",le="1"} 6prometheus_http_request_duration_seconds_bucket{handler="/",le="3"} 6prometheus_http_request_duration_seconds_bucket{handler="/",le="8"} 6prometheus_http_request_duration_seconds_bucket{handler="/",le="20"} 6prometheus_http_request_duration_seconds_bucket{handler="/",le="60"} 6prometheus_http_request_duration_seconds_bucket{handler="/",le="120"} 6prometheus_http_request_duration_seconds_bucket{handler="/",le="+Inf"} 6 // 这个实际上等于总申请数prometheus_http_request_duration_seconds_sum{handler="/"} 0.00016767900000000003 // 上述样本求和 sumprometheus_http_request_duration_seconds_count{handler="/"} 6 // 这次采样总申请数Go SDK :// 观测这个值落在了哪个 buckte 中Observe(float64)Summary个性:与 Histogram 相似实用:与 Histogram 相似示例:垃圾回收进展工夫# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.# TYPE go_gc_duration_seconds summarygo_gc_duration_seconds{quantile="0"} 4.2354e-05go_gc_duration_seconds{quantile="0.25"} 9.222e-05go_gc_duration_seconds{quantile="0.5"} 0.000133648go_gc_duration_seconds{quantile="0.75"} 0.000193116go_gc_duration_seconds{quantile="1"} 0.00906632go_gc_duration_seconds_sum 0.064656275go_gc_duration_seconds_count 295Go SDK:// 观测值Observe(float64)Summary VS Histogram雷同 ...

December 10, 2021 · 3 min · jiezi

关于golang:golang标准库os模块File文件读操作

golang规范库os模块-File文件读操作本文视频教程:https://www.bilibili.com/vide... 关注公众号,取得课程材料和源码 这里完结和File构造体相干的文件读操作 package mainimport ( "fmt" "os")// 关上敞开文件func openCloseFile() { // 只能读 f, _ := os.Open("a.txt") fmt.Printf("f.Name(): %v\n", f.Name()) // 依据第二个参数 能够读写或者创立 f2, _ := os.OpenFile("a1.txt", os.O_RDWR|os.O_CREATE, 0755) fmt.Printf("f2.Name(): %v\n", f2.Name()) err := f.Close() fmt.Printf("err: %v\n", err) err2 := f2.Close() fmt.Printf("err2: %v\n", err2)}// 创立文件func createFile() { // 等价于:OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666) f, _ := os.Create("a2.txt") fmt.Printf("f.Name(): %v\n", f.Name()) // 第一个参数 目录默认:Temp 第二个参数 文件名前缀 f2, _ := os.CreateTemp("", "temp") fmt.Printf("f2.Name(): %v\n", f2.Name())}// 读操作func readOps() { // 循环读取 /* f, _ := os.Open("a.txt") for { buf := make([]byte, 6) n, err := f.Read(buf) fmt.Println(string(buf)) fmt.Printf("n: %v\n", n) if err == io.EOF { break } } f.Close() */ /* buf := make([]byte, 10) f2, _ := os.Open("a.txt") // 从5开始读10个字节 n, _ := f2.ReadAt(buf, 5) fmt.Printf("n: %v\n", n) fmt.Printf("string(buf): %v\n", string(buf)) f2.Close() */ // 测试 a目录上面有b和c目录 /* f, _ := os.Open("a") de, _ := f.ReadDir(-1) for _, v := range de { fmt.Printf("v.IsDir(): %v\n", v.IsDir()) fmt.Printf("v.Name(): %v\n", v.Name()) } */ // 定位 f, _ := os.Open("a.txt") f.Seek(3, 0) buf := make([]byte, 10) n, _ := f.Read(buf) fmt.Printf("n: %v\n", n) fmt.Printf("string(buf): %v\n", string(buf)) f.Close()}func main() { // openCloseFile() // createFile() readOps()}

December 10, 2021 · 1 min · jiezi

关于golang:golang标准库os模块文件目录相关

golang规范库os模块-文件目录相干本文视频教程:https://www.bilibili.com/vide... 关注公众号,取得课程材料和源码 os规范库实现了平台(操作系统)无关的编程接口。 https://pkg.go.dev/std package mainimport ( "fmt" "os")// 创立文件func createFile() { f, err := os.Create("test.txt") if err != nil { fmt.Printf("err: %v\n", err) } else { fmt.Printf("f: %v\n", f) }}// 创立目录func createDir() { // 创立单个目录 /* err := os.Mkdir("test", os.ModePerm) if err != nil { fmt.Printf("err: %v\n", err) } */ err := os.MkdirAll("test/a/b", os.ModePerm) if err != nil { fmt.Printf("err: %v\n", err) }}// 删除目录func removeDir() { /* err := os.Remove("test.txt") if err != nil { fmt.Printf("err: %v\n", err) } */ err := os.RemoveAll("test") if err != nil { fmt.Printf("err: %v\n", err) }}// 取得工作目录func getWd() { dir, err := os.Getwd() if err != nil { fmt.Printf("err: %v\n", err) } else { fmt.Printf("dir: %v\n", dir) }}// 批改工作目录func chWd() { err := os.Chdir("d:/") if err != nil { fmt.Printf("err: %v\n", err) } fmt.Println(os.Getwd())}// 取得长期目录func getTemp() { s := os.TempDir() fmt.Printf("s: %v\n", s)}// 重命名文件func renameFile() { err := os.Rename("test.txt", "test2.txt") if err != nil { fmt.Printf("err: %v\n", err) }}// 读文件func readFile() { b, err := os.ReadFile("test2.txt") if err != nil { fmt.Printf("err: %v\n", err) } else { fmt.Printf("b: %v\n", string(b[:])) }}// 写文件func writeFile() { s := "hello world" os.WriteFile("test2.txt", []byte(s), os.ModePerm)}func main() { // createFile() // createDir() // removeDir() // removeDir() // getWd() // chWd() // renameFile() // readFile() // writeFile() // getTemp()}

December 10, 2021 · 1 min · jiezi

关于golang:Go语言学习查缺补漏ing-Day7

作者:ReganYue 起源:恒生LIGHT云社区 Go语言学习查缺补漏ing Day7零、前言因为笔者根底不牢,在应用Go语言的时候常常遇到很多摸不着头脑的问题,所以笔者下定决心好好对Go语言进行查漏补缺,本【Go语言查缺补漏ing】系列次要是帮忙老手Gopher更好的理解Go语言的易错点、重难点。心愿各位看官可能喜爱,点点赞、关注一下呗! 一、再谈defer的执行程序大家来看一看这段代码: package mainimport "fmt"type Person struct { age int}func main() { person := &Person{28} //A defer func(p *Person) { fmt.Println(p.age) }(person) //B defer fmt.Println(person.age) //C defer func() { fmt.Println(person.age) }() person.age = 21}后面咱们介绍过defer的执行程序,然而我明天又遇到新问题,于是这里又补充介绍这个defer的程序问题。 这个程序运行后果是: 212821咱们都晓得defer的执行程序是先进后出,所以执行程序是C、B、A。 B中 defer fmt.Println(person.age)输入28,为什么呢? 因为这里是将28作为defer()函数的参数,会把28推入栈中进行缓存,失去执行这条defer语句时就把它拿进去。所以输入28. 而A中: defer func(p *Person) { fmt.Println(p.age) }(person)defer()函数是将构造体Person的地址进行缓存,当后续扭转这个地址的内值时,后续输入时这里就会输入那个地址内扭转后的值。所以B defer语句执行时从地址中取出的值是29. 而C defer语句理由很简略: defer func() { fmt.Println(person.age) }()就是无参匿名函数的一种情景。闭包援用,person.age扭转就会扭转。 二、哪种切片的申明比拟好?为什么?var a []inta := []int{}这里第一种申明的是nil切片,而第二种申明是创立一个长度以及容量为零的空切片。 第一种切片申明办法比拟好,因为它这种申明形式不占用空间,而第二种申明后会占用一部分空间。 三、获得构造体成员的几种办法package mainimport "fmt"type S struct { m string}func f() *S { return &S{"ReganYue"}}func main() { p := f() p2 := *f() fmt.Println(p.m, p2.m)}咱们运行可能发现: ...

December 10, 2021 · 2 min · jiezi

关于golang:详解布隆过滤器的原理和实现

为什么须要布隆过滤器设想一下遇到上面的场景你会如何解决: 手机号是否反复注册用户是否参加过某秒杀流动伪造申请大量 id 查问不存在的记录,此时缓存未命中,如何防止缓存穿透针对以上问题惯例做法是:查询数据库,数据库硬扛,如果压力并不大能够应用此办法,放弃简略即可。 改良做法:用 list/set/tree 保护一个元素汇合,判断元素是否在汇合内,工夫复杂度或空间复杂度会比拟高。如果是微服务的话能够用 redis 中的 list/set 数据结构, 数据规模十分大此计划的内存容量要求可能会十分高。 这些场景有个共同点,能够将问题形象为:如何高效判断一个元素不在汇合中?那么有没有一种更好计划能达到工夫复杂度和空间简单双优呢? 有!布隆过滤器。 什么是布隆过滤器布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器能够用于检索一个元素是否在一个汇合中,它的长处是空间效率和查问工夫都远远超过个别的算法。 工作原理布隆过滤器的原理是,当一个元素被退出汇合时,通过 K 个散列函数将这个元素映射成一个位数组中的 K 个点(offset),把它们置为 1。检索时,咱们只有看看这些点是不是都是 1 就(大概)晓得汇合中有没有它了:如果这些点有任何一个 0,则被检元素肯定不在;如果都是 1,则被检元素很可能在。这就是布隆过滤器的根本思维。 简略来说就是筹备一个长度为 m 的位数组并初始化所有元素为 0,用 k 个散列函数对元素进行 k 次散列运算跟 len(m)取余失去 k 个地位并将 m 中对应地位设置为 1。 布隆过滤器优缺点长处: 空间占用极小,因为自身不存储数据而是用比特位示意数据是否存在,某种程度有窃密的成果。插入与查问工夫复杂度均为 O(k),常数级别,k 示意散列函数执行次数。散列函数之间能够互相独立,能够在硬件指令层减速计算。毛病: 误差(假阳性率)。无奈删除。误差(假阳性率)布隆过滤器能够 100% 判断元素不在汇合中,然而当元素在汇合中时可能存在误判,因为当元素十分多时散列函数产生的 k 位点可能会反复。维基百科有对于假阳性率的数学推导(见文末链接)这里咱们间接给论断(实际上是我没看懂...),假如: 位数组长度 m散列函数个数 k预期元素数量 n冀望误差__在创立布隆过滤器时咱们为了找到适合的 m 和 k ,能够依据预期元素数量 n 与 来推导出最合适的 m 与 k 。 java 中 Guava, Redisson 实现布隆过滤器估算最优 m 和 k 采纳的就是此算法: ...

December 9, 2021 · 4 min · jiezi

关于golang:MySQL教程

MySQL教程MySQL 入门教程MySQL 装置MySQL 治理MySQL PHP 语法MySQL 连贯MySQL 创立数据库MySQL 删除数据库MySQL 抉择数据库MySQL 数据类型MySQL 创立数据表MySQL 删除数据表MySQL 插入数据MySQL 查问数据MySQL where 子句MySQL UPDATE 查问MySQL DELETE 语句MySQL LIKE 子句MySQL 排序MySQL 分组MySQL 连贯的应用MySQL NULL 值解决MySQL 正则表达式MySQL 事务MySQL ALTER命令MySQL 索引MySQL 长期表MySQL 复制表MySQL 元数据MySQL 序列应用MySQL 解决反复数据MySQL 及 SQL 注入MySQL 导出数据MySQL 导入数据MySQL函数MySQL DATE_ADD() 函数MySQL DATE_SUB() 函数MySQL DATEDIFF() 函数MySQL DATE_FORMAT() 函数MySQL NOW() 函数MySQL CURDATE() 函数MySQL CURTIME() 函数MySQL DATE() 函数MySQL EXTRACT() 函数MySQL 字符串连贯CONCAT()函数MySQL 字符串截取SUBSTRING()函数MySQL 数学函数mysql substr() 函数

December 9, 2021 · 1 min · jiezi

关于golang:sql教程

SQL教程SQL 教程SQL 简介SQL 语法SQL Select抉择SQL SELECT DISTINCTSQL 查问子句SQL 与,或,非SQL 按关键字排序SQL 在表中插入SQL 空值SQL 更新SQL 删除SQL高级教程SQL SELECT TOP, LIMIT, ROWNUMSQL LIKE 运算符SQL Wildcards 通配符SQL IN 运算符SQL BETWEEN运算符SQL 通用数据类型SQL 语句疾速参考SQL Join连贯SQL 外部连贯SQL 左连贯SQL 右连贯SQL 残缺内部连贯SQL 自连贯SQL UNION 运算符SQL SELECT INTO 语句SQL INSERT INTO SELECT 语句SQL 撤销索引、表以及数据库SQL CREATE DATABASE 语句SQL CREATE TABLE 语句SQL ALTER TABLE 语句SQL AUTO INCREMENT 字段SQL CREATE VIEW、REPLACE VIEW、 DROP VIEW 语句SQL Server 和 MySQL 中的 Date 函数SQL NULL 值 – IS NULL 和 IS NOT NULLSQL进阶SQL Aliases 别名SQL 束缚SQL NOT NULL 束缚SQL UNIQUE 束缚SQL PRIMARY KEY 束缚SQL FOREIGN KEY 束缚SQL DEFAULT 束缚SQL CHECK 束缚SQL JOIN 连贯SQL UNION 子句SQL 克隆数据表SQL 索引SQL 子查问SQL ALTER TABLE 命令SQL TRUNCATE TABLE 命令SQL 解决反复数据SQL 应用视图SQL 注入SQL HAVING 子句SQL 事务SQL 应用序列SQL 通配符SQL 长期表SQL MS Access、MySQL 和 SQL Server 数据类型SQL函数SQL MAX() 函数SQL MIN() 函数SQL COUNT() 函数SQL AVG() 函数SQL SUM() 函数SQL 日期函数SQL 函数SQL FIELD()函数SQL FIRST() 函数SQL LAST() 函数SQL GROUP BY 语句SQL HAVING 子句SQL UPPER(),LOWER()函数SQL UPPER()函数SQL LOWER()函数SQL UCASE() 函数SQL LCASE() 函数SQL MID() 函数SQL LEN() 函数SQL ROUND() 函数SQL NOW() 函数SQL FORMAT() 函数SQL SQRT() 函数SQL RAND() 函数SQL CONCAT() 函数SQL ISNULL()、NVL()、IFNULL() 和 COALESCE() 函数SQL REPLACE()函数SQL TRIM()函数日期函数MySQL NOW() 函数MySQL CURDATE() 函数MySQL CURTIME() 函数MySQL DATE() 函数MySQL EXTRACT() 函数MySQL DATE_ADD() 函数MySQL DATE_SUB() 函数MySQL DATEDIFF() 函数MySQL DATE_FORMAT() 函数SQL Server GETDATE() 函数SQL Server DATEPART() 函数SQL Server DATEADD() 函数SQL Server DATEDIFF() 函数SQL Server CONVERT() 函数

December 9, 2021 · 1 min · jiezi

关于golang:golang函数总结

golang 函数本文视频教程:https://www.bilibili.com/vide... 关注公众号,支付课程材料及源码 golang函数简介函数的go语言中的一级公民,咱们把所有的性能单元都定义在函数中,能够重复使用。函数蕴含函数的名称、参数列表和返回值类型,这些形成了函数的签名(signature)。 go语言中函数个性go语言中有3种函数:一般函数、匿名函数(没有名称的函数)、办法(定义在struct上的函数)。receivergo语言中不容许函数重载(overload),也就是说不容许函数同名。go语言中的函数不能嵌套函数,但能够嵌套匿名函数。函数是一个值,能够将函数赋值给变量,使得这个变量也成为函数。函数能够作为参数传递给另一个函数。函数的返回值能够是一个函数。函数调用的时候,如果有参数传递给函数,则先拷贝参数的正本,再将正本传递给函数。函数参数能够没有名称。go语言中函数的定义和调用函数在应用之前必须先定义,能够调用函数来实现某个工作。函数能够反复调用,从而达到代码重用。 go语言函数定义语法func function_name( [parameter list] ) [return_types]{ 函数体}语法解析: func:函数由 func 开始申明function_name:函数名称,函数名和参数列表一起形成了函数签名。[parameter list]:参数列表,参数就像一个占位符,当函数被调用时,你能够将值传递给参数,这个值被称为理论参数。参数列表指定的是参数类型、程序、及参数个数。参数是可选的,也就是说函数也能够不蕴含参数。return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些性能不须要返回值,这种状况下 return_types 不是必须的。函数体:函数定义的代码汇合。go语言函数定义实例定义一个求和函数 func sum(a int, b int) (ret int) { ret = a + b return ret}定义一个比拟两个数大小的函数 func compare(a int, b int) (max int) { if a > b { max = a } else { max = b } return max}go语言函数调用当咱们要实现某个工作时,能够调用函数来实现。调用函数要传递参数,如何有返回值能够取得返回值。 func main() { s := sum(1, 2) fmt.Printf("s: %v\n", s) max := compare(1, 2) fmt.Printf("max: %v\n", max)}运行后果 ...

December 8, 2021 · 5 min · jiezi

关于golang:golang操作redis

装置redis本文视频教程:https://www.bilibili.com/vide... 下载redis 这里在windows平台下测试 https://github.com/MicrosoftArchive/redis/releases启动server 执行redis-server.exe C:\Program Files\Redis>redis-server.exe[12092] 10 Aug 13:29:08.616 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server.exe /path/to/redis.conf _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 3.0.504 (00000000/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 | `-._ `._ / _.-' | PID: 12092 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-'[12092] 10 Aug 13:29:08.619 # Server started, Redis version 3.0.504[12092] 10 Aug 13:29:08.619 * The server is now ready to accept connections on port 6379客户端测试 ...

December 8, 2021 · 3 min · jiezi

关于golang:golang操作MongoDB总结

下载安装MongoDB本文视频教程:https://www.bilibili.com/vide... 关注公众号,支付课程材料和源码 下载地址: https://www.mongodb.com/download-center/community关上客户端mongo.exe创立数据库use go_db;创立汇合 db.createCollection("student");下载安装驱动并连贯数据库下载地址: https://www.mongodb.com/download-center/community关上客户端mongo.exe创立数据库use go_db;创立汇合 db.createCollection("student");下载驱动go get github.com/mongodb/mongo-go-driver连贯mongoDBpackage mainimport ( "context" "fmt" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "log")var client *mongo.Clientfunc initDB() { // 设置客户端连贯配置 clientOptions := options.Client().ApplyURI("mongodb://localhost:27017") // 连贯到MongoDB var err error client, err = mongo.Connect(context.TODO(), clientOptions) if err != nil { log.Fatal(err) } // 查看连贯 err = client.Ping(context.TODO(), nil) if err != nil { log.Fatal(err) } fmt.Println("Connected to MongoDB!")}func main() { initDB()}运行后果 Connected to MongoDB!BSON简介MongoDB中的JSON文档存储在名为BSON(二进制编码的JSON)的二进制示意中。与其余将JSON数据存储为简略字符串和数字的数据库不同,BSON编码扩大了JSON示意,使其蕴含额定的类型,如int、long、date、浮点数和decimal128。这使得应用程序更容易牢靠地解决、排序和比拟数据。 连贯MongoDB的Go驱动程序中有两大类型示意BSON数据:D和Raw。 类型D家族被用来简洁地构建应用本地Go类型的BSON对象。这对于结构传递给MongoDB的命令特地有用。D家族包含四类: ...

December 8, 2021 · 3 min · jiezi

关于golang:GO进阶训练营完结fsgsd

download:GO进阶训练营【完结】构造字符串 你会常常需要打印字符串。要是有很多变量,避免上面这样: name = "Raymond" age = 22 born_in = "Oakland, CA" string = "Hello my name is " + name + "and I'm " + str(age) + " years old. I was born in " + born_in + "." print(string)额,这看起来多乱呀?你可能用个丑陋简洁的方法来代替, .format 。 这样做: name = "Raymond" age = 22 born_in = "Oakland, CA" string = "Hello my name is {0} and I'm {1} years old. I was born in {2}.".format(name, age, born_in) print(string)返回tuple元组 ...

December 8, 2021 · 2 min · jiezi

关于golang:gorm声明模型

gorm申明模型本文视频教程:https://www.bilibili.com/vide... 模型定义模型是规范的 struct,由 Go 的根本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成 例如: type User struct { ID uint Name string Email *string Age uint8 Birthday *time.Time MemberNumber sql.NullString ActivatedAt sql.NullTime CreatedAt time.Time UpdatedAt time.Time}约定GORM 偏向于约定,而不是配置。默认状况下,GORM 应用 ID 作为主键,应用构造体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并应用 CreatedAt、UpdatedAt 字段追踪创立、更新工夫 遵循 GORM 已有的约定,能够缩小您的配置和代码量。如果约定不合乎您的需要,GORM 容许您自定义配置它们 gorm.ModelGORM 定义一个 gorm.Model 构造体,其包含字段 ID、CreatedAt、UpdatedAt、DeletedAt // gorm.Model 的定义type Model struct { ID uint `gorm:"primaryKey"` CreatedAt time.Time UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"`}您能够将它嵌入到您的构造体中,以蕴含这几个字段,详情请参考 嵌入构造体 高级选项字段级权限管制可导出的字段在应用 GORM 进行 CRUD 时领有全副的权限,此外,GORM 容许您用标签管制字段级别的权限。这样您就能够让一个字段的权限是只读、只写、只创立、只更新或者被疏忽 ...

December 8, 2021 · 2 min · jiezi

关于golang:gorm概述

gorm概述本文视频教程:https://www.bilibili.com/vide... ORM简介对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库(如mysql数据库)存在的互不匹配的景象的技术。简略的说,ORM是通过应用形容对象和数据库之间映射的元数据,将程序中的对象主动长久化到关系数据库中。 装置go get -u gorm.io/gormgo get -u gorm.io/driver/sqlite疾速入门package mainimport ( "gorm.io/gorm" "gorm.io/driver/mysql")type Product struct { gorm.Model Code string Price uint}func main() { dsn := "root:123456@tcp(127.0.0.1:3306)/golang_db?charset=utf8mb4&parseTime=True&loc=Local" if err != nil { panic("failed to connect database") } // 迁徙 schema db.AutoMigrate(&Product{}) // Create db.Create(&Product{Code: "D42", Price: 100}) // Read var product Product db.First(&product, 1) // 依据整形主键查找 db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录 // Update - 将 product 的 price 更新为 200 db.Model(&product).Update("Price", 200) // Update - 更新多个字段 db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段 db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"}) // Delete - 删除 product db.Delete(&product, 1)}原为地址:https://gorm.io/docs/index.html ...

December 8, 2021 · 1 min · jiezi

关于golang:defer和return的执行时机

在Go语言return不是原子操作,分为返回值赋值和RET指令两步。例如:return x实现步骤 返回值 = x执行defer执行SET指令多个defer相似栈,后defer先执行 func main() { out()}func out() () { defer func() {fmt.Println("world")}() defer func() {fmt.Println("hello")}()}输入 helloworldProcess finished with the exit code 0带返回值defer不影响return返回值 func main() { fmt.Println("return out put", out())}func out() int { i := 0 defer func() { i++ // 不影响return返回值 fmt.Println("defer out put ", i) }() return i // 返回值=i=0; i++}输入 defer out put 1return out put 0带命名返回值defer影响return返回值 func main() { fmt.Println("return out put", out())}func out() (i int) { defer func() { i++ // 影响return返回值 fmt.Println("defer out put ", i) }() return 1 // i=1; i++}输入 ...

December 8, 2021 · 1 min · jiezi

关于golang:golang操作MySQL数据库总结

golang操作MySQL数据库总结本文视频链接:https://www.bilibili.com/vide... 关注公众号,下载课程材料和源码: 筹备数据库和表下载安装MySQL https://dev.mysql.com/downloads/mysql/创立一个go_db数据库 create database go_db关上数据库 use go_db创立表 CREATE TABLE user_tbl ( id INTEGER PRIMARY KEY AUTO_INCREMENT, username VARCHAR (20), PASSWORD VARCHAR (20))增加模仿数据 INSERT INTO user_tbl (username, PASSWORD) VALUES ("tom", "123")INSERT INTO user_tbl (username, PASSWORD) VALUES ("kite", "456")装置配置mysql驱动装置驱动 go get -u github.com/go-sql-driver/mysql初始化模块 go mod init m执行go mod tidy go mod tidy导入驱动 package mainimport ( "fmt" "database/sql" _ "github.com/go-sql-driver/mysql")func main() { }取得数据库连贯导入包 package mainimport ( "fmt" "database/sql" _ "github.com/go-sql-driver/mysql")取得连贯 ...

December 8, 2021 · 3 min · jiezi

关于golang:推荐几个可以写到简历上的Go方向优质开源项目需花点心思研究

原文链接:举荐几个能够写到简历上的Go方向优质开源我的项目(需花点心理钻研) 前言哈喽,大家好,我是asong。最近总有读者问我有没有Go语言方向优质的开源我的项目,能够写在简历上那种,一时还真想不起来,花了两天工夫调研了一下,针对有无工作教训的别离举荐几个开源我的项目,上面咱们一起来看一下。 无工作教训对于还在上学的敌人们,除了晓得必要的基础知识外,也要有1-2个拿的出手的我的项目,光有根底,没有实际,很难过来简历这一关,对于学生而言,简略的crud还是要熟练掌握的,接下来就举荐几个文档比拟齐全的web我的项目,入门后能够在此基础上深度开发。 bbs-gobbs-go是一个应用Go语言搭建的开源社区零碎,后端应用技术栈: iris (https://github.com/kataras/iris) Go 语言 mvc 框架gorm (http://gorm.io/) Go 语言 orm 框架Nuxt.js (https://nuxtjs.org/) 基于Vue.js的服务端页面渲染框架,简略、好用、功能强大resty (https://github.com/go-resty/resty) Go 语言好用的 http-clientcron (https://github.com/robfig/cron) 定时工作goquery (https://github.com/PuerkitoBio/goquery) html dom 元素解析还有配套的前端我的项目,基于Vue搭建的,性能还是比拟全面的,通过这个我的项目能够理解开发一个开源社区的设计思路,对于一个新手入门web开发还是很敌对的,然而这个我的项目须要付费能力观看搭建文档,不过代码是开源的,大家能够把源码下载下来本人钻研一下,代码内容不多且简洁,本人深耕几天应该能够把握。 我的项目地址:https://gitee.com/mlogclub/bb... Gin-vue-admin这个我的项目在Go语言畛域还是很闻名的,Gin-vue-admin是一个基于 vue 和 gin 开发的全栈前后端拆散的开发根底平台,集成jwt鉴权,动静路由,动静菜单,casbin鉴权,表单生成器,代码生成器等性能,提供多种示例文件,还配有残缺的文档教程和视频教程。这个我的项目集体感觉是新手入门必看我的项目,跟着做一遍后根本的crud就都把握了,其中分片长传、代码生成器的性能还是挺有借鉴意义的,能够深刻理解一下。这个我的项目不须要介绍太多,文档比拟具体,能够达到手把手入门的水平。 我的项目地址:https://github.com/flipped-au... rpcx当初企业都是由单体利用向微服务架构转型,微服务的实际离不开RPC框架的利用,目前服务治理型的 RPC 框架有dubbo-go、go-zero、go-kit 等,跨语言调用型的 RPC 框架有 Thrift、gRPC、Hessian、Finagle、rpcx 等,对于一个小白而言了解RPC的原理比拟重要,所以能够先从rpcx框架动手,rpcx 是一个分布式的Go语言的RPC 框架,反对Zookepper、etcd、consul多种服务发现形式,多种服务路由形式, 是目前性能最好的 RPC 框架之一,rpcx的文档比拟齐全,有专门的团队保护,是新手入门的不二抉择。 我的项目地址:https://github.com/smallnest/... 文档地址:https://doc.rpcx.io/ go-kit大家能够关注一下go-kit这个微服务项目,基于go-kit能够疾速构建强壮、牢靠、可保护的微服务,go-kit提供了对consul、etcd、zookeeper、eureka等注册核心的反对,有一位大佬开源了一份go-kit微服务实际教程: 观看这个系列的博客:https://juejin.cn/post/684490...源码地址在这里:https://github.com/hwholiday/...go-kit主动生成代码的命令行工具:https://github.com/kujtimiiho...我的项目地址:https://github.com/go-kit/kit 有工作教训曾经有工作教训的敌人们就能够不必看一些根底的我的项目和原理了,能够更多的关注我的项目的架构设计、性能优化、服务治理等,更多的去思考如何保护好一个我的项目,这其实并不需要来看开源框架,更多关注本人我的项目团队的框架,从中找出优缺点去做优化,更加体现本人的价值。如果本人我的项目团队的框架比拟水的话,那么上面就举荐几个优良的开源我的项目供你学习借鉴。 zinxzinx是一个基于Go语言开发的TCP长连贯服务器框架,其能够利用在游戏畛域或其余长连贯畛域;咱们能够学习zinx框架的设计思路,他有残缺的视频教程和文档,通过这个咱们能够齐全了解如何设计一个轻量级并发服务器,而后本人基于zinx本人写一个,并做一些优化,写在简历上岂不是能够吹一吹!!! 我的项目地址:https://github.com/aceld/zinx 文档地址:https://www.kancloud.cn/aceld... 视频地址:https://www.bilibili.com/vide... go-zero对于大多数敌人一进入公司就开始了crud,应用的web框架、rpc框架也都是企业曾经搭建好的,间接就拿来用了,很少有机会参加到如何设计一个web框架、rpc框架之中,然而面试中面试官还爱考查这些货色,所以就须要咱们平时多关注如何设计一款高性能的企业框架,go-zero就一款企业框架,咱们能够从中学习到值得借鉴的的设计;go-zero集成了web和rpc框架,是在20年由好将来开源的一款微服务框架,因为go-zero我的项目还是比拟大的,倡议大家带着目的性去学习,比方我想理解微服务注册与发现的原理实现、自适应负载平衡算法原理与实现,这样咱们就能够带着目的性去查阅源码,总结学习文档并把它摘要进去造成本人的货色,写在简历上吹吹水他不香嘛!!! go-zero的文档体系还不是很欠缺,一些知识点的学习还须要大家本人去总结提炼。 我的项目地址:https://github.com/zeromicro/... go-nsqNSQ是一个基于Go语言的分布式实时音讯平台,可用于大规模零碎中的实时音讯服务,并且每天可能解决数亿级别的音讯,其设计指标是为在分布式环境下运行的去中心化服务提供一个弱小的基础架构。他的弱小就不用多说了,我举荐这个我的项目的起因是让大家去学习nsq是如何设计的,应用起来是简略的,然而如何设计才是重点,面试中如果让你设计一个高性能的实时音讯平台,你晓得该如何设计吗? 我的项目地址:https://github.com/nsqio/go-nsq 学习地址:https://cloud.tencent.com/dev... TidbTidb是NewSQL行业中的代表性产品,由PingCAP公司自主设计、研发的开源分布式关系型数据库,兼容MySQL 5.7 协定和 MySQL 生态等重要个性。目前很多公司都在应用Tidb,解决了关系型数据库、弹性扩大以及寰球散布的问题。Tidb采纳Go语言开发SQL层,下边的分布式存储引擎应用rust语言,应用Tidb具备以下劣势: 反对弹性的扩缩容;反对 SQL,兼容大多数 MySQL 的语法,在大多数场景下能够间接替换 MySQL;默认反对高可用,主动进行数据修复和故障转移;反对 ACID 事务;如果大家相熟Tidb的设计与实现,能够写到简历上,和面试官吹吹水!!! ...

December 7, 2021 · 1 min · jiezi

关于golang:golang切片总结

golang切片本文视频教程:https://www.bilibili.com/vide... 后面咱们学习了数组,数组是固定长度,能够包容雷同数据类型的元素的汇合。当长度固定时,应用还是带来一些限度,比方:咱们申请的长度太大节约内存,太小又不够用。 鉴于上述起因,咱们有了go语言的切片,能够把切片了解为,可变长度的数组,其实它底层就是应用数组实现的,减少了主动扩容性能。切片(Slice)是一个领有雷同类型元素的可变长度的序列。 go语言切片的语法申明一个切片和申明一个数组相似,只有不增加长度就能够了 var identifier []type切片是援用类型,能够应用make函数来创立切片: var slice1 []type = make([]type, len)也能够简写为slice1 := make([]type, len)也能够指定容量,其中capacity为可选参数。 make([]T, length, capacity)这里 len 是数组的长度并且也是切片的初始长度。 go语言切片实例package mainimport "fmt"func main() { var names []string var numbers []int fmt.Printf("names: %v\n", names) fmt.Printf("numbers: %v\n", numbers) fmt.Println(names == nil) fmt.Println(numbers == nil)}运行后果 names: []numbers: []truetruego语言切片的长度和容量切片领有本人的长度和容量,咱们能够通过应用内置的len()函数求长度,应用内置的cap()函数求切片的容量。 实例 package mainimport "fmt"func main() { var names = []string{"tom", "kite"} var numbers = []int{1, 2, 3} fmt.Printf("len: %d cap: %d\n", len(names), cap(names)) fmt.Printf("len: %d cap: %d\n", len(numbers), cap(numbers)) var s1 = make([]string, 2, 3) fmt.Printf("len: %d cap: %d\n", len(s1), cap(s1))}运行后果 ...

December 7, 2021 · 3 min · jiezi

关于golang:Prometheus-快速入门01

Prometheus 是什么Prometheus 是 SoundCloud 公司开源的零碎监控告警工具。2016 年,继 k8s 后,作为第二个托管我的项目退出了云原生计算基金会。这个我的项目领有着十分沉闷的开发者和用户社区,随着云原生和 k8s的推广,越来越多的公司的运维都是应用 Prometheus + Grafana(可视化) 的这一套。 Prometheus 以时序数据的模式收集和存储其指标,同时反对增加自定义 label 的可选键值对 监控对象硬件状态:电源状态、CPU 状态、机器温度、风扇状态...服务器根底:CPU,内存,磁盘,网络 应用状况数据库: MySQL, ES ...中间件:Nginx, MQ..利用:QPS,接口延时,线程数...Prometheus 劣势其余计划 Zabbix: 1998 年诞生... 属于传统主机监控,次要用于物理主机,交换机,网络等监控Graphite: 专一于两件事,存储时序数据, 可视化数据, 其它性能都要装置插件实现, Prometheus 功能丰富:趋势,查问...InfluxDB: 时序数据库... 监控局部本人搞,prometheus 不仅仅局限于存储时序数据Nagios:90 年代诞生...Sensu :能够看作 Nagiosde 的降级版本Open-falcon:小米开源,社区活跃度个别劣势 云原生反对好,K8s 和 Etcd 等一列我的项目都提供了对 Prometheus 的原生反对,是目前容器监控最风行的计划Prometheus 属于一站式监控告警平台,依赖少,功能齐全。多维数据模型,聚合统计更不便弱小的查问语句劣势 数据存储扩展性不够好Prometheus 架构Sever:抓取(pull 模式)和存储时序数据,提供查问接口Exporter:服务监控上报数据,如 MySQL、Redis、Node ExporterAlertManger:告警告诉Pushgetaway: 反对被动向 Sever push 数据,实用于生命周期短暂的批处理的工作。 装置与应用装置 官网教程 走过的一个坑 Prometheus 应用 docker 装置,node exporter 在本机跑,网络不通。倡议不应用 docker 装置前提 mac装置 prometheus。能关上 http://localhost:9090/装置 node export。能关上 http://localhost:9100/配置好了 prometheus.yml(配置 node exporter 地址,server 通过这个地址 pull 数据)。http://localhost:9090/ 抉择 targes,呈现两个,如下图即装置胜利。 ...

December 7, 2021 · 1 min · jiezi

关于golang:golang流程控制总结

go语言中的流程管制本文视频教程地址:https://www.bilibili.com/vide... go语言中的条件条件语句是用来判断给定的条件是否满足(表达式值是否为true或者false),并依据判断的后果(真或假)决定执行的语句,go语言中的条件语句也是这样的。 go语言中的条件语句蕴含如下几种状况if 语句:if 语句 由一个布尔表达式后紧跟一个或多个语句组成。if...else 语句: if 语句 后能够应用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。if 嵌套语句: 你能够在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。switch 语句: switch 语句用于基于不同条件执行不同动作。select 语句: select 语句相似于 switch 语句,然而select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。go语言中的循环语句go语言中的循环只有for循环,去除了while、do while循环,应用起来更加简洁。 for循环。for range循环。go语言中的流程管制关键字breakcontinuegotogolang中的if语句go语言中的if语句和其余语言中的相似,都是依据给定的条件表达式运算后果来,判断执行流程。 go语言if语句语法if 布尔表达式 { /* 在布尔表达式为 true 时执行 */}留神:在go语言中 布尔表达式不必应用括号。go语言if语句实例演示依据布尔值flag判断 import "fmt"func test1() { var flag = true if flag { fmt.Println("flag is true") } fmt.Printf("程序运行完结")}func main() { test1()}程序运行后果 flag is true程序运行完结依据年龄判断是否成年 ...

December 7, 2021 · 6 min · jiezi

关于golang:Go高级工程师实战营jk

download:Go高级工程师实战营后盾代码都是利用的 1.【get形式】使用jquery的get json与后盾交互 前端js代码片段 ?12345678var data= {'a': $('input[name="a"]').val(),'b': $('input[name="b"]').val()}$.getJSON($SCRIPT_ROOT + '/_add_numbers',data, function(data) {$('#result').text(data.result);$('input[name=a]').focus().select();});后端pthon代码如下 ?123456 ajax,Get形式与js交互(非表单)采纳了flask框架@app.route('/_add_numbers')def add_numbers():"""Add two numbers server side, ridiculous but well...""" a = request.args.get('a', 0, type=int) b = request.args.get('b', 0, type=int) log.info(a) log.info(b) return jsonify(result=a + b)2.【万能形式】使用jquery的ajax与后盾交互,设置不同的参数,可能get也可能post 下面的例子用ajax形式,前端代码如下 ?1234567891011121314151617181920212223var data= { 'a': $('input[name="a"]').val(), 'b': $('input[name="b"]').val() }{# $.getJSON($SCRIPT_ROOT + '/_add_numbers',data, function(data) {#}{# $('#result').text(data.result);#}{# $('input[name=a]').focus().select();#}{# });#} $.ajax({ type: 'get', url: $SCRIPT_ROOT + '/_add_numbers', data: data, contentType: 'application/json; charset=UTF-8', dataType: 'json', success: function(data) { $('#result').text(data.result); $('input[name=a]').focus().select(); }, error: function(xhr, type,xxx) { alert('error ') } });后盾代码不便依然是 ...

December 5, 2021 · 1 min · jiezi

关于golang:Go并不需要Java风格的GC

本文首发于 https://robberphex.com/go-does-not-need-a-java-style-gc/。 像Go、Julia和Rust这样的古代语言不须要像Java c#所应用的那样简单的垃圾收集器。但这是为什么呢? 咱们首先要理解垃圾收集器是如何工作的,以及各种语言分配内存的形式有什么不同。首先,咱们看看为什么Java须要如此简单的垃圾收集器。 本文将涵盖许多不同的垃圾收集器话题: 为什么Java依赖疾速GC?我将介绍Java语言自身中的一些设计抉择,它们会给GC带来很大压力。内存碎片及其对GC设计的影响。为什么这对Java很重要,但对Go就不那么重要。值类型以及它们如何扭转GC。分代垃圾收集器,以及Go为什么不须要它。逃逸剖析 —— Go用来缩小GC压力的一个技巧。压缩垃圾收集器 —— 这在Java中很重要,然而Go却不须要它。为什么?并发垃圾收集 —— Go通过应用多线程运行并发垃圾收集器来解决许多GC挑战。为什么用Java更难做到这一点。对Go GC的常见批评,以及为什么这种批评背地的许多假如往往是有缺点的或齐全谬误的。为什么Java比其余语言更须要疾速的GC基本上,Java将内存治理齐全外包给它的垃圾收集器。事实证明,这是一个微小的谬误。然而,为了可能解释这一点,我须要介绍更多的细节。 让咱们从头说起。当初是1991年,Java的工作曾经开始。垃圾收集器当初很风行。相干的钻研看起来很有前途,Java的设计者们把赌注押在高级垃圾收集器上,它可能解决内存治理中的所有挑战。 因为这个起因,Java中的所有对象——除了整数和浮点值等根本类型——都被设计为在堆上调配。在探讨内存调配时,咱们通常会辨别所谓的堆和栈。 栈应用起来十分快,但空间无限,只能用于那些在函数调用的生命周期之内的对象。栈只实用于局部变量。 堆可用于所有对象。Java基本上疏忽了栈,抉择在堆上调配所有货色,除了整数和浮点等根本类型。无论何时,在Java中写下 new Something()耗费的都是堆上的内存。 然而,就内存应用而言,这种内存治理实际上相当低廉。你可能认为创立一个32位整数的对象只须要4字节的内存。 class Knight { int health;}然而,为了让垃圾收集器可能工作,Java存储了一个头部信息,蕴含: 类型/Type — 标识对象属于的类或它的类型。锁/Lock — 用于同步语句。标记/Mark — 标记和革除(mark and sweep)垃圾收集器应用。这些数据通常为16字节。因而,头部信息与理论数据的比例是4:1。Java对象的c++源代码定义为:OpenJDK基类: class oopDesc { volatile markOop _mark; // for mark and sweep Klass* _klass; // the type}内存碎片接下来的问题是内存碎片。当Java调配一个对象数组时,它实际上是创立一个援用数组,这些援用指向内存中的其余对象。这些对象最终可能扩散在堆内存中。这对性能十分不利,因为古代微处理器不读取单个字节的数据。因为开始传输内存数据是比较慢的,每次CPU尝试拜访一个内存地址时,CPU会读取一块间断的内存。 这块间断的内存块被称为cache line 。CPU有本人的缓存,它的大小比内存小得多。CPU缓存用于存储最近拜访的对象,因为这些对象很可能再次被拜访。如果内存是碎片化的,这意味着cache line也会被碎片化,CPU缓存将被大量无用的数据填满。CPU缓存的命中率就会升高。 Java如何克服内存碎片为了解决这些次要的毛病,Java维护者在高级垃圾收集器上投入了大量的资源。他们提出了压缩(compact)的概念,也就是说,把对象挪动到内存中相邻的块中。这个操作十分低廉,将内存数据从一个地位挪动到另一个地位会耗费CPU周期,更新指向这些对象的援用也会耗费CPU周期。 这些援用被应用的时候,垃圾收集器没法更新它们。所以更新这些援用须要暂停所有的线程。这通常会导致Java程序在挪动对象、更新援用和回收未应用内存的过程中呈现数百毫秒的齐全暂停。 减少复杂性为了缩小这些长时间的暂停,Java应用了所谓的分代垃圾收集器(generational garbage collector)。这些都是基于以下前提: 在程序中调配的大多数对象很快就会被开释。因而,如果GC花更多工夫来解决最近调配的对象,那么应该会缩小GC的压力。这就是为什么Java将它们调配的对象分成两组: 老年对象——在GC的屡次标记和革除操作中幸存下来的对象。每次标记和扫描操作时,会更新一个分代计数器,以跟踪对象的“年龄”。年老对象——这些对象的“年龄”较小,也就是说他们是最近才调配进去的。Java更踊跃地解决、扫描最近调配的对象,并查看它们是否应该被回收或挪动。随着对象“年龄”的增长,它们会被移出年老代区域。 所有这些优化会带来更多的复杂度,它须要更多的开发工作量。它须要领取更多的钱来雇佣更优良的开发者。 古代语言如何防止与Java雷同的缺点古代语言不须要像Java和c#那样简单的垃圾收集器。这是在设计这些语言时,并没有像Java一样依赖垃圾回收器。 type Point struct { X, Y int}var points [15000]Point在下面的Go代码示例中,咱们调配了15000个Point对象。这仅仅调配了一次内存,产生了一个指针。在Java中,这须要15000次内存调配,每次调配产生一个援用,这些利用也要独自治理起来。每个Point对象都会有后面提到的16字节头部信息开销。而不论是在Go语言、Julia还是Rust中,你都不会看到头部信息,对象通常是没有这些头部信息的。 ...

December 5, 2021 · 2 min · jiezi

关于golang:Go笔记03即时通信Demo

即时通信DemoV0.1 根底Server构建实现新用户连贯胜利后,在server端揭示的性能server.go package mainimport ( "fmt" "net")type Server struct { Ip string Port int}//创立一个server的接口func NewServer(ip string,port int) *Server { server := &Server{ Ip: ip, Port: port, } return server}//启动服务器的接口// 定义对象(类)的办法: func (对象类型参数)办法名(参数列表)(返回值列表){ }// 如果想通过办法批改对象,那么倡议传递对象的地址 (构造体是值传递,通过构造体的指针批改构造体(地址传递)) (也能够通过返回值批改对象)//func (obj *MyInt) add() { } // 对象调用时,会主动将对象的地址传给objfunc (this *Server) Start() { //socket listen listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d",this.Ip,this.Port)) if err != nil { fmt.Println("net.listen tcp err:", err) } //close listen socket defer listener.Close() for { //accept conn, err := listener.Accept() if err != nil { fmt.Println("listen accept err:", err) continue } //do handler go this.Handler(conn) }}//链接胜利,执行业务func (this *Server) Handler(conn net.Conn) { fmt.Println("Connection Success...")}main.go ...

December 5, 2021 · 10 min · jiezi

关于golang:go语言环境搭建

GOLANG环境变量GOROOT golang装置门路。不应扭转其默认设置。以windows环境为例,GOROOT默认在C盘根目录,若装置过程中更改其门路,则须要手动再更改环境变量。GOPATH golang工作目录主动Golang采纳Module的形式治理我的项目后,GOPATH目录曾经不是那么重要了,目前次要用来寄存依赖的Module库,生成的可执行文件等。GOPATH环境变量的配置参考下面的装置Go,配置到/etc/profile或者Windows下的零碎变量里。这个目录咱们能够依据本人的设置指定,比方我的Mac在$HOME/code/go下,Window的能够放到d:\code\go下等。该目录下有3个子目录,他们别离是: .├── bin├── pkg└── srcbin文件夹寄存go install命名生成的可执行文件,能够把$GOPATH/bin门路退出到PATH环境变量里,就和咱们下面配置的$GOROOT/bin一样,这样就能够间接在终端里应用咱们go开发生成的程序了。pkg文件夹是存在go编译生成的文件。src寄存的是非Go Module我的项目源代码。

December 5, 2021 · 1 min · jiezi

关于golang:Golang-中由零值和-gob-库的特性引起的-BUG

0 起源就在往年9月份,我负责的部门平台我的项目公布了一个新版本,该版本同时上线了一个新性能,简略说有点相似定时工作。头一天一切正常,但第二天呈现了极少数工作没有失常执行(曾经暂停的工作继续执行,失常的工作反而没有执行)的状况。 问题的景象让我和另一个共事的第一反馈是定时工作执行的逻辑呈现了问题。但在咱们消耗了大量的工夫去DEBUG、测试后,发现问题的基本并不在性能逻辑,而是一段曾经上线了一年并且没有动过的底层公共代码。这段代码的外围就是本篇文章的主人公gob,引发问题的本源则是go语言的一个个性:零值。 后文中我会用一个更简化的例子形容这个 BUG。 1 gob 与零值先简略介绍一下gob和零值。 1.1 零值零值是 Go 语言中的一个个性,简略说就是:Go 语言会给一些没有被赋值的变量提供一个默认值。譬如上面这段代码: package mainimport ( "fmt")type person struct { name string gender int age int}func main() { p := person{} var list []byte var f float32 var s string var m map[string]int fmt.Println(list, f, s, m) fmt.Printf("%+v", p)}/* 后果输入[] 0 map[]{name: gender:0 age:0}*/零值在很多时候的确为开发者带来了不便,但也有许多不喜爱它的人认为零值的存在使得代码从语法层面上不谨严,带来了一些不确定性。譬如我行将在后文中详细描述的问题。 1.2 gobgob是 Go 语言自带的规范库,在encoding/gob中。gob其实是go binary的简写,因而从它的名称咱们也能够猜到,gob该当与二进制相干。 实际上gob是 Go 语言独有的以二进制模式序列化和反序列化程序数据的格局,相似 Python 中的 pickle。它最常见的用法是将一个对象(构造体)序列化后存储到磁盘文件,在须要应用的时候再读取文件并反序列化进去,从而达到对象长久化的成果。 例子我就不举了,本篇也不是gob的应用专题。这是它的官网文档,对gob用法不相熟的敌人们能够看一下文档中的Example局部,或者间接看我后文中形容问题用到的例子。 2 问题2.1 需要在本文的结尾,我简略叙述了问题的起源,这里我用一个更简略的模型来开展形容。 ...

December 4, 2021 · 3 min · jiezi

关于golang:Go面试题一聊聊你理解的defer关键字

大家好,我是大道哥。 defer关键字是咱们工作中常常用到的go语言个性,也是面试官比拟青眼的一个知识点,明天通过这篇文章带各位道友彻底把握它。 defer两大个性defer是golang中的一个关键字,它次要具备两大个性: 提早调用: 在以后函数执行实现后调用执行。func f1(){ defer fmt.Println("hello world") fmt.Println("hello defer!")}输入后果: $ go run main.gohello defer!hello world后进先出: 多个defer函数时,执行程序为后进先出。func f2(){ defer fmt.Println("hello 1!") defer fmt.Println("hello 2!") defer fmt.Println("hello 3!") fmt.Println("hello defer!")}输入后果 $ go run main.gohello defer!hello 3!hello 2!hello 1!defer与return的执行程序defer与return的执行程序,是面试时常常考查的一点,须要道友们好好了解。 首先,咱们举个栗子,看如下状况下代码的输入后果。 func f1() (r int){ defer func(){ r++ }() return 0}func f2() (r int) { t:=5 defer func() { t = t+5 }() return t}func f3() (r int) { defer func(r int) { r = r+5 }(r) return 0}func main(){ fmt.Println(f1()) fmt.Println(f2()) fmt.Println(f3())}倡议敌人们先思考下答案,再往后看。 ...

December 3, 2021 · 2 min · jiezi

关于golang:Docker-系列docker-学习九Compose-内容编排官网初步体验

【Docker 系列】docker 学习九,Compose 内容编排官网初步体验咱们后面的文章学习了 docker ,为什么还要 Compose 呢?Compose到底是个啥玩意? Docker Compose 能够来轻松的高效的治理容器,定义运行多个容器 咱们一起来看看官网的介绍 docs Compose 是什么Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features. 讲了三个点: Compose 能够定义和运行多个容器须要应用给到 YAML 配置文件单个命令就能够创立和启动所有的服务Compose works in all environments: production, staging, development, testing, as well as CI workflows. You can learn more about each case in Common Use Cases. ...

December 3, 2021 · 3 min · jiezi

关于golang:JuiceFS-数据读写流程详解

对于文件系统而言,其读写的效率对整体的零碎性能有决定性的影响,本文咱们将通过介绍 JuiceFS 的读写申请解决流程,让大家对 JuiceFS 的个性有更进一步的理解。 写入流程JuiceFS 对大文件会做多级拆分(参见 JuiceFS 如何存储文件),以进步读写效率。在解决写申请时,JuiceFS 先将数据写入 Client 的内存缓冲区,并在其中按 Chunk/Slice 的模式进行治理。Chunk 是依据文件内 offset 按 64 MiB 大小拆分的间断逻辑单元,不同 Chunk 之间齐全隔离。每个 Chunk 内会依据利用写申请的理论状况进一步拆分成 Slices;当新的写申请与已有的 Slice 间断或有重叠时,会间接在该 Slice 上进行更新,否则就创立新的 Slice。 Slice 是启动数据长久化的逻辑单元,其在 flush 时会先将数据依照默认 4 MiB 大小拆分成一个或多个间断的 Blocks,并上传到对象存储,每个 Block 对应一个 Object;而后再更新一次元数据,写入新的 Slice 信息。显然,在利用程序写状况下,只须要一个不停增长的 Slice,最初仅 flush 一次即可;此时能最大化施展出对象存储的写入性能。 以一次简略的 JuiceFS 基准测试为例,其第一阶段是应用 1 MiB IO 程序写 1 GiB 文件,数据在各个组件中的模式如下图所示: 留神:图中的压缩和加密默认未开启。欲启用相干性能须要在 format 文件系统的时候增加 --compress value 或 --encrypt-rsa-key value 选项。这里再放一张测试过程中用 stats 命令记录的指标图,能够更直观地看到相干信息: ...

December 3, 2021 · 2 min · jiezi

关于golang:开始读-Go-源码了

原文链接: 开始读 Go 源码了 学完 Go 的基础知识曾经有一段时间了,那么接下来应该学什么呢?有几个方向能够思考,比如说 Web 开发,网络编程等。 在下一阶段的学习之前,写了一个开源我的项目|Go 开发的一款分布式惟一 ID 生成零碎,如果你对这个我的项目感兴趣的话,能够在 GitHub 上拿到源码。 在写我的项目的过程中,发现一个问题。实现性能是没问题的,但不晓得本人写的代码是不是合乎 Go 的格调,是不是够优雅。所以我感觉相比于持续学习利用开发,不如向底层后退,打好根底,打好写 Go 代码的根底。 所以,我决定开始读 Go 规范库源码,Go 一共有 150+ 规范库,想要全副读完的话不是不可能,但相对是一项大工程,心愿本人能坚持下去。 为什么从 Go 规范库的源码开始读呢?因为最近也看了一些 Go 底层原理的书,说实话,像 goroutine 调度,gc 垃圾回收这些内容,基本就看不懂。这要是一上来就读这部分代码,恐怕间接就放弃 Go 语言学习了。 而规范库就不一样了,有一部分代码基本不波及底层原理,实现也绝对简略,同时又能对 Go 的理念加深了解,作为入门再好不过了。而后再由简入深,循序渐进,就像打怪降级一样,一步一步驯服 Go。 说了这么多,那到底应该怎么读呢?我想到了一些办法: 看官网规范库文档。看网上其他人的技术文章。写一些例子来练习如何应用。如果能够的话,本人实现规范库的性能。将本人的浏览心得总结输入。能够通过下面的一种或几种办法相结合,而后再一直浏览一直总结,最终找到一个齐全适宜本人的办法。 上面是我总结的一些规范库及性能介绍: archive/tar 和 /zip-compress:压缩(解压缩)文件性能。fmt-io-bufio-path/filepath-flag: fmt:提供格式化输入输出性能。io:提供根本输入输出性能,大多数是围绕零碎性能的封装。bufio:缓冲输入输出性能的封装。path/filepath:用来操作在以后零碎中的指标文件名门路。flag:提供对命令行参数的操作。strings-strconv-unicode-regexp-bytes: strings:提供对字符串的操作。strconv:提供将字符串转换为根底类型的性能。unicode:为 unicode 型的字符串提供非凡的性能。regexp:正则表达式性能。bytes:提供对字符型分片的操作。index/suffixarray:子字符串疾速查问。math-math/cmath-math/big-math/rand-sort: math:根本的数学函数。math/cmath:对复数的操作。math/rand:伪随机数生成。sort:为数组排序和自定义汇合。math/big:大数的实现和计算。container-/list-/ring-/heap: list:双链表。ring:环形链表。heap:堆。compress/bzip2-/flate-/gzip-/lzw-zlib: compress/bzip2:实现 bzip2 的解压。flate:实现 deflate 的数据压缩格局,如 RFC 1951 所述。gzip:实现 gzip 压缩文件的读写。lzw:Lempel Ziv Welch 压缩数据格式实现。zlib:实现 zlib 数据压缩格局的读写。context:用来简化对于解决单个申请的多个 goroutine 之间与申请域的数据、勾销信号、截止工夫等相干操作。crypto-crypto/md5-crypto/sha1: ...

December 3, 2021 · 1 min · jiezi

关于golang:Golang-的骚操作golinkname

背景在看源码时,一些源码办法没有办法体,难道阐明这些办法为空?例如:time.Now 调用的 now(), time.Sleep , reflect.makechan// Provided by package runtime.func now() (sec int64, nsec int32, mono int64)func Sleep(d Duration)func makechan(typ *rtype, size int) (ch unsafe.Pointer)在写代码时,如果咱们想应用别的包下没有导出的办法或者变量时,怎么操作go:linkname 的用法实际上,上述提到的三个没有办法体的办法,其实现都在 src/runtime包下 time.now timestub.go 文件中//go:linkname time_now time.nowfunc time_now() (sec int64, nsec int32, mono int64) { sec, nsec = walltime() return sec, nsec, nanotime()}time.Sleep time.go 文件中// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.//go:linkname timeSleep time.Sleepfunc timeSleep(ns int64) { if ns <= 0 { return } gp := getg() t := gp.timer if t == nil { t = new(timer) gp.timer = t } t.f = goroutineReady t.arg = gp t.nextwhen = nanotime() + ns if t.nextwhen < 0 { // check for overflow. t.nextwhen = maxWhen } gopark(resetForSleep, unsafe.Pointer(t), waitReasonSleep, traceEvGoSleep, 1)}reflect.makechan//go:linkname reflect_makechan reflect.makechanfunc reflect_makechan(t *chantype, size int) *hchan { return makechan(t, size)}咱们能够看到具体实现都具备 go:linkname, 能够揣测就是这个货色把两个不同包下的函数链接到一起了 ...

December 3, 2021 · 2 min · jiezi

关于golang:Go语言快速入门笔记02

协程(Go程) goroutine协程:co-routineGolang对协程的解决: 协程 => goroutine,内存几KB,能够大量应用灵便调度,可常切换GMP相干材料: Go work-stealing 调度器 goroutine 根本模型和调度器策略详解 Go 有一个能够利用多核处理器的 M:N 调度器. 任何时候, M 个 goroutine 都须要在 N 个 OS 线程上进行调度, 这些线程运行在最多 GOMAXPROCS 数量的处理器上.G:goroutine协程 P:processor处理器(最大GOMAXPROCS) M:thread线程 有一个 P 相干的本地和全局 goroutine 队列. 每个 M 应该被调配给一个 P. 如果被阻塞或者在零碎调用中, P (们) 可能没有 M (们). 任何时候,最多只有 GOMAXPROCS 数量的 P. 任何时候, 每个 P 只能有一个 M 运行. 如果须要, 更多的 M (们) 能够由调度器创立. 调度器的设计策略复用线程 work stealing机制:未充分利用的处理器会被动去寻找其余处理器的线程并 窃取 一些hand off机制: 如果正在运行的协程 G1 阻塞了,然而其余的调度器都在解决本人的业务,没有工夫去偷 work stealing 这阻塞的 G1 下面队列中的其余协程,咱们就唤醒一个线程,或者开启一个线程,将咱们之前的在调度器和其余没有阻塞的协程切换过来;G 阻塞完结后,如果还要运行,就放到其余调度器 P 下面的协程队列中,如果不执行,就将 M1 线程休眠或销毁即可利用并行:通过GOMAXPROCS限定P的个数抢占:每个goroutine最多执行10ms(co-routine只能期待CPU被动开释)全局G队列:当P的本地队列为空时,M先从全局队列拿G放到P的本地队列,再从其它P窃取创立goroutinepackage mainimport ( "fmt" "time")//子go程func newTask(){ i := 0 for { i++ fmt.Printf("newTask Goroutine i=%d\n", i) time.Sleep(1 * time.Second) }}//主go程func main() { //创立子go程执行newTask() go newTask() fmt.Println("main Goroutine exit")//主go程完结后子go程也会销毁 i := 0 for { i++ fmt.Printf("main Goroutine i=%d\n", i) time.Sleep(1 * time.Second) }}匿名goroutine ...

December 1, 2021 · 3 min · jiezi

关于golang:参加Tinykv的一些总结

Talent Plan KV学习营对于Talent Plan KV训练营我想我有必要介绍一下,这是PingCAP公司推出的一套开源分布式KV存储实战课程,这课程一共蕴含了4子项目: Project 1须要参与者独立实现一个单机的KV ServerProject 2须要基于Raft算法实现分布式键值数据库服务端Project 3须要在Project 2的根底上反对多个Raft集群Project 4须要Project 3的根底上反对分布式事务难度都是阶梯式的,如果能实现tinykv 所有子项目,产出一个分布式kv数据库,置信这也是一个很大的播种,据我所知目前也就麻省理工学院有一套MIT 6.824课程,Ping Cap推出这套tinykv课程也是相当于补救了国内这块课程的空白了。 我以后加入的本次我的项目要求的是Go语言去实现这些Lab,或者读者你看到这篇文章的时候可能换到其余语言上了比如说Rust,当然至于用什么编程语言去实现,都是不重要的问题,重要的是在论文浏览局部,这就好比你看懂了一栋大楼的设计图纸,而后语言就是一个堆砖头的工具。 论文地址:https://github.com/kvbase/raft-thesis-zh_cn因为举办方要求参赛者不得以任何形式间接贴每个我的项目的答案代码,当然我认为这么做是对的,然而举办方激励参赛者写一些对于实现lab的解题思路分享,早晨抽时间把第一个lab实现了,本文这篇将写写Project 1的怎么入坑的。 Standalone KV Server第一个lab是一个典型的TDD开发的例子,什么是TDD如果读者不理解本人去Google吧。Project 1是要基于BadgerDB作为存储引擎的去实现出题者预留的API接口的,而后官网在我的项目根目录建了一个makefile文件,参与者只须要make project1即可查看Project 1实现状况。 BadgerDB是dgraph.io开发的一款基于 Log Structured Merge (LSM) Tree 的 key-value 本地数据库, 应用Go 开发。 开发这个我的项目你得须要有Go mod根底,没有本人去补吧。 执行了make project1能够看到抛出了一大堆异样,这些异样起因就是官网工程师给你写的单元测试没有跑通过,你要做的只须要把/tinykv/kv/server/server_test.go下的所有的单元测试用例调用的api外面的性能实现即可。 第一个你要实现的package standalone_storageimport ( "github.com/pingcap-incubator/tinykv/kv/config" "github.com/pingcap-incubator/tinykv/kv/storage" "github.com/pingcap-incubator/tinykv/proto/pkg/kvrpcpb")// StandAloneStorage is an implementation of `Storage` for a single-node TinyKV instance. It does not// communicate with other nodes and all data is stored locally.type StandAloneStorage struct { // Your Data Here (1).}func NewStandAloneStorage(conf *config.Config) *StandAloneStorage { // Your Code Here (1). return nil}func (s *StandAloneStorage) Start() error { // Your Code Here (1). return nil}func (s *StandAloneStorage) Stop() error { // Your Code Here (1). return nil}func (s *StandAloneStorage) Reader(ctx *kvrpcpb.Context) (storage.StorageReader, error) { // Your Code Here (1). return nil, nil}func (s *StandAloneStorage) Write(ctx *kvrpcpb.Context, batch []storage.Modify) error { // Your Code Here (1). return nil}第二个你要实现的package serverimport ( "context" "github.com/pingcap-incubator/tinykv/proto/pkg/kvrpcpb")// The functions below are Server's Raw API. (implements TinyKvServer).// Some helper methods can be found in sever.go in the current directory// RawGet return the corresponding Get response based on RawGetRequest's CF and Key fieldsfunc (server *Server) RawGet(_ context.Context, req *kvrpcpb.RawGetRequest) (*kvrpcpb.RawGetResponse, error) { // Your Code Here (1). return nil, nil}// RawPut puts the target data into storage and returns the corresponding responsefunc (server *Server) RawPut(_ context.Context, req *kvrpcpb.RawPutRequest) (*kvrpcpb.RawPutResponse, error) { // Your Code Here (1). // Hint: Consider using Storage.Modify to store data to be modified return nil, nil}// RawDelete delete the target data from storage and returns the corresponding responsefunc (server *Server) RawDelete(_ context.Context, req *kvrpcpb.RawDeleteRequest) (*kvrpcpb.RawDeleteResponse, error) { // Your Code Here (1). // Hint: Consider using Storage.Modify to store data to be deleted return nil, nil}// RawScan scan the data starting from the start key up to limit. and return the corresponding resultfunc (server *Server) RawScan(_ context.Context, req *kvrpcpb.RawScanRequest) (*kvrpcpb.RawScanResponse, error) { // Your Code Here (1). // Hint: Consider using reader.IterCF return nil, nil}对应的单元测试文件是tinykv/kv/server/server_test.go,测试用例官网工程师曾经写好了,你只须要把底层代码实现,跑通单元测试即可实现Project 1,我这里提醒一下Project 1能够看成一个适配器模式,只是进行了一层封装,写实现的或者测试单元测试的时候能够一个一个测试来测试,先把单元测试全副正文掉,而后实现一个解正文一个,跑一个,good luck!。 ...

December 1, 2021 · 2 min · jiezi

关于golang:轻松一刻Go-118修复了一个经典bug

前言大家在写Go的时候,初期应该都会遇到过上面的编译报错: declared but not used比方上面的代码示例: // example2.gopackage main func main() { a := 10a = 1}执行 go run example2.go,会报如下编译谬误: ./example2.go:5:2: a declared but not used 起因下面的报错,实际上是因为对于规范Go编译器,局部变量必须至多有一次被作为右值(r-value: right-hand-side-value)应用过。 下面的例子里局部变量a都是左值,并没有作为右值被应用过,因而编译报错。 咱们来看一个新的例子,大家感觉上面的代码,执行go run example2.go的后果是什么? // example2.gopackage main func main() { a := 10func() { a = 1}()} 论断按理来说,下面的示例外头,局部变量a在闭包里没有被作为右值应用过,还是应该会编译报错”declared but not used“。 然而大家晓得么,Go规范编译器对于”declared but not used“这样的查看,也会有bug。 下面的代码如果是Go1.18之前的版本,执行的话,后果是没有任何报错。 从Go1.18版本开始,解决了局部变量在闭包里没被应用然而编译器不报错的bug,Go1.18开始编译会报错”declared but not used“。 官网阐明如下: The Go 1.18 compiler now correctly reports "declared but not used" errorsfor variables that are set inside a function literal but are never used. Before Go 1.18,the compiler did not report an error in such cases. This fixes long-outstanding compilerissue #8560. As a result of this change,(possibly incorrect) programs may not compile anymore. The necessary fix isstraightforward: fix the program if it was in fact incorrect, or use the offendingvariable, for instance by assigning it to the blank identifier _.Since go vet always pointed out this error, the number of affectedprograms is likely very small.对于这个bug批改的探讨,感兴趣的能够参考cmd/compile: consistently report "declared but not used" errors· Issue #49214。 ...

December 1, 2021 · 1 min · jiezi

关于golang:Go配置管理探讨

目录配置分类最佳实际配置管理参考链接1. 配置分类环境配置利用在部署的时候应该确定的信息,这些信息不应该写在配置文件或者配置核心,而是应该由部署平台在利用启动的时候注入,例如k8s间接在容器启动的时候注入 动态配置利用资源初始化的时候须要的信息,如服务的根本信息、Mysql、Redis、Mongodb等配置信息,个别是放在我的项目的根目录下的动态文件 动静配置应用程序在运行是的时候须要的一些配置,相似某些性能开关,个别是在治理后盾去管制 2. 最佳实际2.1 形式一json动态文件治理配置文件配置 { "server": { "addr": "0.0.0.0:8000" }, "mysql": { "driver": "mysql", "dsn": "root:@tcp(127.0.0.1:3306)/testdb?parseTime=True" }}我的项目依赖全局的Config map package mainimport ( "database/sql" "encoding/json" "net/http" "os")var Config = make(map[string]map[string]string)func main() { file, err := os.Open("/path/to/config/config.json") if err != nil { panic(err) } decoder := json.NewDecoder(file) err = decoder.Decode(&Config) if err != nil { panic(err) } defer file.Close() db, err := NewMysql(Config["mysql"]["driver"], Config["mysql"]["driver"]) if err != nil { panic(err) } server := &http.Server{ Addr: Config["server"]["addr"], } err = server.ListenAndServe() if err != nil { panic(err) }}// 连贯mysqlfunc NewMysql(driver, dsn string) (*sql.DB, error) { return sql.Open(driver, dsn)}2.2 形式二创立一个Config构造体类型,业务依赖这个构造体,并且将json配置解析到这个构造体 ...

November 30, 2021 · 3 min · jiezi

关于golang:一文讲透一致性哈希的原理和实现

为什么须要一致性哈希首先介绍一下什么是哈希 Hash,个别翻译做散列,或音译为哈希,是把任意长度的输出(又叫做预映射pre-image)通过散列算法变换成固定长度的输入,该输入就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输出的空间,不同的输出可能会散列成雷同的输入,所以不可能从散列值来确定惟一的输出值。简略的说就是一种将任意长度的消息压缩到某一固定长度的音讯摘要的函数。 在分布式缓存服务中,常常须要对服务进行节点增加和删除操作,咱们心愿的是节点增加和删除操作尽量减少数据-节点之间的映射关系更新。 如果咱们应用的是哈希取模( hash(key)%nodes ) 算法作为路由策略: 哈希取模的毛病在于如果有节点的删除和增加操作,对 hash(key)%nodes 后果影响范畴太大了,造成大量的申请无奈命中从而导致缓存数据被从新加载。 基于下面的毛病提出了一种新的算法:一致性哈希。一致性哈希能够实现节点删除和增加只会影响一小部分数据的映射关系,因为这个个性哈希算法也经常用于各种均衡器中实现零碎流量的平滑迁徙。 一致性哈希工作原理 首先对节点进行哈希计算,哈希值通常在 2^32-1 范畴内。而后将 2^32-1 这个区间首尾连贯形象成一个环并将节点的哈希值映射到环上,当咱们要查问 key 的指标节点时,同样的咱们对 key 进行哈希计算,而后顺时针查找到的第一个节点就是指标节点。 依据原理咱们剖析一下节点增加和删除对数据范畴的影响。 节点增加 只会影响新增节点与前一个节点(新增节点逆时针查找的第一个节点)之间的数据。 节点删除 只会影响删除节点与前一个节点(删除节点逆时针查找的第一个节点)之间的数据。 这样就完了吗?还没有,试想一下如果环上的节点数量非常少,那么十分有可能造成数据分布不均衡,实质上是环上的区间散布粒度太粗。 怎么解决呢?不是粒度太粗吗?那就退出更多的节点,这就引出了一致性哈希的虚构节点概念,虚构节点的作用在于让环上的节点区间散布粒度变细。 一个实在节点对应多个虚构节点,将虚构节点的哈希值映射到环上,查问 key 的指标节点咱们先查问虚构节点再找到实在节点即可。 代码实现基于下面的一致性哈希原理,咱们能够提炼出一致性哈希的外围性能: 增加节点删除节点查问节点咱们来定义一下接口: ConsistentHash interface { Add(node Node) Get(key Node) Node Remove(node Node)}事实中不同的节点服务能力因硬件差别可能各不相同,于是咱们心愿在增加节点时能够指定权重。反馈到一致性哈希当中所谓的权重意思就是咱们心愿 key 的指标节点命中概率比例,一个实在节点的虚构节点数量多则意味着被命中概率高。 在接口定义中咱们能够减少两个办法:反对指定虚构节点数量增加节点,反对按权重增加。实质上最终都会反馈到虚构节点的数量不同导致概率分布差别。 指定权重时:理论虚构节点数量 = 配置的虚构节点 * weight/100 ConsistentHash interface { Add(node Node) AddWithReplicas(node Node, replicas int) AddWithWeight(node Node, weight int) Get(key Node) Node Remove(node Node)}接下来思考几个工程实现的问题: ...

November 30, 2021 · 3 min · jiezi

关于golang:第1章对象存储简介

第1章、对象存储简介1.1 和传统网络存储的区别传统的网络存储次要有两类,别离是 NAS 和 SAN NAS (Network Attachment Storage):对于客户端来说,NAS 是一个网络上的文件服务器 SAN (Storage Area Network):和 NAS 的区别是,SAN 提供了块存储,文件系统的形象由客户端治理。对于客户端来说,SAN 就是一块磁盘。 1.1.1 数据的治理形式网络文件系统:数据以一个个文件的模式进行治理块存储:数据以数据块的模式来进行治理,数据块除地址外没有其余额定的背景信息对象存储:数据以对象的形式来进行治理,蕴含三局部 数据:该对象中存储的数据自身。一个对象能够用来保留大量无构造的数据,如歌、照片、文档元数据:对象的形容信息,如:创立工夫、文件大小等标识符:用于援用该对象,具备全局唯一性。通常用对象的散列值来做其标识符1.1.2 拜访数据的形式网络文件系统:客户端通过 NFS 等网络协议拜访某个服务器上存储的文件块存储:通过数据块地址拜访 SAN 上的数据块对象存储:通过 REST 网络服务拜访对象REST(Representational State Transfer), REST 网络服务通过规范HTTP服务对网络资源提供一套事后定义的无状态操作。

November 29, 2021 · 1 min · jiezi

关于golang:收藏Go开发IDE-GoLand常用快捷键

前言快捷键对开发的重要性就不再赘述了,在本文章列出本人罕用的快捷键,当做一个cheatsheet,忘记了随时回来查找。 能够通过FIle->Settings->Keymap->Main Menu对罕用的快捷键做自定义设置。 也能够通过File-> Manage IDE Settings -> Export Settings / Import Settings对设置做导入导出。 上面列出平时Go开发中必备的快捷键,能够显著晋升开发效率。 代码导航快捷键跳转到对应文件 Shift + Alt + O:这是自己自定义的。 能够在File->Settings->Keymap->Main Menu->Navigate->Search Everything里设置自定义快捷键。 搜寻文件外面的内容 Ctrl + Shift + F后退和后退 Ctrl + Alt + 向左箭头 Ctrl + Alt + 向右箭头 查看定义 Ctrl + B 查看被应用状况 Alt + F7 或者应用Ctrl + Shift + F 搜寻 调试快捷键设置断点和勾销断点 Ctrl+F8:设置断点和勾销断点 断点执行 F9:跳到下一个断点 单步执行 F8:完结以后步骤,执行下一步。如果以后步骤调用了函数,不会进入函数里,能够应用F7进入到函数外面 跳到函数外面和跳出函数 F7:进入调用的函数外面 Shift+F8:跳出调用的函数 查看以后所有断点,并且能够设置断点执行的条件 Ctrl+Shift+F8 启动Debug调试模式 Shift + F9 完结调试 ...

November 29, 2021 · 1 min · jiezi

关于golang:gRPC配置记录

go运行第一个gRPC程序装置插件go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1配置环境变量将%GOPATH%\bin增加到Path中 创立我的项目我的项目构造├─practice│ │ go.mod│ │ go.sum│ ││ ├─client│ │ ├─sample_client│ │ │ client.go│ ││ ├─proto│ │ │ helloworld.proto│ ││ └─server│ ├─simple_server│ │ server.go│编辑helloword.protosyntax = "proto3";package proto; // 包名option go_package = '/grpc/service'; // 指定生成的go代码所寄存的门路,不必提前创立service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {}}message HelloRequest { string name = 1;}message HelloReply { string message = 1;}生成go代码# 进入寄存.proto门路下cd proto# 生成代码protoc --go_out=. --go-grpc_out=. *.proto# 最初一个参数为源文件生成后的目录构造├─practice│ │ go.mod│ │ go.sum│ ││ ├─client│ │ ├─sample_client│ │ │ client.go│ ││ ├─proto│ │ │ helloworld.proto│ │ ││ │ └─grpc│ │ └─service│ │ helloworld.pb.go│ │ helloworld_grpc.pb.go│ ││ └─server│ ├─simple_server│ │ server.go│编辑client.gopackage mainimport ( "context" "flag" "google.golang.org/grpc" "log" pb "practice/proto/grpc/service" "time")const ( defaultName = "world")var ( addr = flag.String("addr", "localhost:50051", "the address to connect to") name = flag.String("name", defaultName, "Name to greet"))func main() { flag.Parse() // 建设连贯 conn, err := grpc.Dial(*addr, grpc.WithInsecure()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() // 实例化client c := pb.NewGreeterClient(conn) // 调用rpc,期待同步响应 ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name}) if err != nil { log.Fatalf("could not greet: %v", err) } log.Printf("Greeting: %s", r.GetMessage())}server.go ...

November 29, 2021 · 2 min · jiezi

关于golang:我给-Go-语言-开发了-6-个在线工具

工具快速访问JSON 转 GO: https://www.printlove.cn/tool...YAML 转 GO: https://www.printlove.cn/tool...SQL 转 go-zero Model: https://printlove.cn/tools/sq...SQL 转 GORM Model: https://www.printlove.cn/tool...SQL 转 ElasticSearch DSL: https://printlove.cn/tools/sq...SQL 转 entgo schema: https://printlove.cn/tools/sq...JSON转GO网址:https://www.printlove.cn/tool... 1. 有两种模式转化-开展:json中的所有对象都创立为新的struct转化-嵌套:json中的对象都蕴含到一个struct中2. 自定义tag默认转化后的tag是json,也能够自定义,比方能够改为:gorm 3. 效果图 YAML转GO网址:https://www.printlove.cn/tool... 将 yaml 格局主动转化为 Go Struct 构造。 效果图 SQL 转 ent网址:https://printlove.cn/tools/sq... 1. 效果图 2. 性能此工具提供将 SQL 语句转化为 ent schema提供常见的数据库类型到 field 函数的转化SQL 转 ElasticSearch DSL网址:https://printlove.cn/tools/sq... 1. 效果图 2. 以后反对[x] sql and expression[x] sql or expression[x] equal(=) support[x] not equal(!=) support[x] gt(>) support[x] gte(>=) support[x] lt(<) support[x] lte(<=) support[x] sql in (eg. id in (1,2,3) ) expression[x] sql not in (eg. id not in (1,2,3) ) expression[x] paren bool support (eg. where (a=1 or b=1) and (c=1 or d=1))[x] sql like expression (currently use match phrase, perhaps will change to wildcard in the future)[x] sql order by support[x] sql limit support[x] sql not like expression[x] field missing check[x] support aggregation like count(*), count(field), min(field), max(field), avg(field)[x] support aggregation like stats(field), extended_stats(field), percentiles(field) which are not standard sql function[ ] null check expression(is null/is not null)[ ] join expression[ ] having support ...

November 29, 2021 · 1 min · jiezi

关于golang:基于channel的通信模型实践

前言 channel 作为 Go 外围的数据结构和 Goroutine 之间的通信形式,Channel 是撑持 Go 语言高性能并发编程模型的重要构造本节会介绍管道 Channel 的设计原理、数据结构和常见操作,例如 Channel 的创立、发送、接管和敞开。 在进入主题内容之前,读者须要先把握下表中的不同状态下的channel执行Read、Write、close操作所会产生的后果。 图来自 曹大 Go 语言中最常见的、也是常常被人提及的设计模式就是:不要通过共享内存的形式进行通信,而是应该通过通信的形式共享内存。尽管咱们在 Go 语言中也能应用共享内存加互斥锁进行通信,然而 Go 语言提供了一种不同的并发模型,即通信顺序进程(Communicating sequential processes,CSP)。Goroutine 和 Channel 别离对应 CSP 中的实体和传递信息的媒介,Goroutine 之间会通过 Channel 传递数据。 本文将会介绍基于channel实现的多种通信模型 。 MPSC:多生产者单消费者模型对于MPSC的利用场景中,多个生产者负责生产数据,只有一个消费者来生产数据, 而这个模型又可分为两种实现形式: 多个生产者是专用一个channel 来和消费者通信应用本人独有的channel来和消费者通信变种一:生产者共用channel 如图所示,右边有多个生产goroutine往公共的channel中写入数据,左边只有一个生产goroutine从这个channel中读取数据进行解决。 根底版咱们首先定义传递的音讯构造体定义: `type Msg struct { in int}` 而后实现生产者如下,其中参数 sendChan就是生产者和消费者进行通信的channel // 生产者func producer(sendChan chan Msg) { for i := 0; i < 10; i++ { sendChan <- Msg{in: i} }}消费者以及音讯处理函数定义如下,其中参数 sendChan就是生产者和消费者进行通信的channel,以后音讯处理函数process目前只是把音讯内容打印进去。 ...

November 29, 2021 · 3 min · jiezi

关于golang:golang浅析rune数据类型

场景在golang中获取字符串长度的时候,第一个想法就是应用len()函数,在字符串蕴含中文的时候,程序错了。编写了test.go测试文件,代码如下所示。 package mainimport ( "fmt")func main() { str := "test杨先森" fmt.Println("len(str)",len(str))}执行test.go文件,执行后果如下所示。 问题最后我认为字符串长度应该是4个英文字母+3个汉字最后,最初后果是13。对,我没有看错就是13。那惟一的可能,一个中文在这里被解析为3个字符了,而golang默认编码正好是utf-8。 那么我该怎么获取到字符串最实在的长度呢?我这里想获取4个英文字母+3三个汉字,长度为7呢? 解决方案在这里须要引入两种形式 //golang中的unicode/utf8包提供了用utf-8获取长度的办法 fmt.Println("RuneCountInString:", utf8.RuneCountInString(str)) //通过rune类型解决unicode字符 fmt.Println("rune:", len([]rune(str)))在test.go文件增加下面的代码,代码如下所示。 package mainimport ( "fmt" "unicode/utf8")func main() { str := "test杨先森" //golang中string底层是通过byte数组实现的,间接应用len 理论是在按字节长度计算,golang默认应用utf-8编码的,所以一个汉字占3个字节。 fmt.Println("len(str)", len(str)) //以下两种都能够失去str的字符串长度 //golang中的unicode/utf8包提供了用utf-8获取长度的办法 fmt.Println("RuneCountInString:", utf8.RuneCountInString(str)) //通过rune类型解决unicode字符 fmt.Println("rune:", len([]rune(str)))}最终获取到了想要的字符串长度。 参考文献:中文英文不同编码方式占位几何?https://segmentfault.com/a/11...

November 29, 2021 · 1 min · jiezi

关于golang:了解Goroutine-和-Channel

Goroutine什么是GoroutineGoroutine是Golang特有的并发体,是一种轻量级的"线程"Go中最根本的执行单元,每个Goroutine独立执行每一个Go程序至多有一个Goroutine:主Goroutine。当程序启动时,它会主动创立。func main() { say() // 运行中,期待后果 go say() fmt.Println("end") // 不须要期待say()的执行后果}func say(){ fmt.Println("hello world")}Vs Os Thread零碎线程 Os Thread每个零碎线程有固定大小的栈,个别默认2M,这个栈次要用来保留函数递归调用时参数和局部变量,由内核调度 固定大小的栈就会带来问题 空间节约空间可能又不够,存在栈溢出的危险Goroutine由Go的调度器调度,刚创立的时候很小(2kb或者4kb),会依据须要动静地伸缩栈的大小(支流实现中栈的最大值可达到1GB)。 因为启动的代价很小,所以咱们能够轻易地启动成千上万个Goroutine。 通过示例理解1. 多个goroutine同时运行运行的程序由调度器决定,不须要相互依赖 func main() { fmt.Println("Started") for i := 0; i < 10; i++ { go execute(i) } time.Sleep(time.Second * 1) fmt.Println("Finished")}func execute(id int) { fmt.Printf("id: %d\n", id)}2. 图片并发下载func main() { urls := []string{ "https://pic.netbian.com/uploads/allimg/210925/233922-163258436234e8.jpg", "https://pic.netbian.com/uploads/allimg/210920/180354-16321322345f20.jpg", "https://pic.netbian.com/uploads/allimg/210916/232432-16318058722f4d.jpg", } for _,url := range urls{ go downloadFile(url) } time.Sleep(time.Second)}func downloadFile(URL string) error { //Get the response bytes from the url response, err := http.Get(URL) if err != nil { return err } defer response.Body.Close() if response.StatusCode != 200 { return errors.New("Received non 200 response code") } //Create a empty file file, err := os.Create(path.Base(URL)) if err != nil { return err } defer file.Close() //Write the bytes to the fiel _, err = io.Copy(file, response.Body) if err != nil { return err } return nil}Recover每个Goroutine都要有recover机制,因为当一个Goroutine抛panic的时候只有本身可能捕捉到其它Goroutine是没有方法捕获的。 ...

November 29, 2021 · 6 min · jiezi

关于golang:撸了一个可调试-gRPC-的-GUI-客户端

前言平时大家写完 gRPC 接口后是如何测试的?往往有以下几个办法: 写单测代码,本人模仿客户端测试。能够搭一个 gRPC-Gateway 服务,这样就能够在 postman 中进行模仿。但这两种办法都不是特地优雅;第一种办法当申请构造体嵌套特地简单时,在代码中保护起来就不是很直观;而且代码会特地长。 第二种办法在 postman 中与申请 HTTP 接口一样,看起来十分直观;但须要额为保护一个 gRPC-Gateway 服务,同时接口定义发生变化时也得从新公布,应用起来稍显简单。 于是我通过一番搜寻找到了两个看起来还不错的工具: BloomRPChttps://github.com/fullstorydev/grpcui 首先看 BloomRPC 页面好看,性能也很欠缺;但却有个十分好受的中央,那就是不反对 int64 数据的申请, 会有精度问题。 这里我写了一个简略的接口,间接将申请的 int64 返回回来。func (o *Order) Create(ctx context.Context, in *v1.OrderApiCreate) (*v1.Order, error) { fmt.Println(in.OrderId) return &v1.Order{ OrderId: in.OrderId, Reason: nil, }, nil}会发现服务端收到的数据精度曾经失落了。 这个在咱们大量应用 int64 的业务中十分好受,大部分接口都没法用了。 grpcui 是我在应用了 BloomRPC 一段时间之后才发现的工具,性能也比较完善; BloomRPC 中的精度问题也不存在。 但因为我之前曾经习惯了在 BloomRPC 中去调试接口,加上日常开发过程中我的浏览器简直都是开了几十个 tap 页面,导致在其中找到 grpcui 不是那么不便。 所以我就想着能不能有一个相似于 BloomRPC 的独立 APP,也反对 int64 的工具。 筹备找了一圈,貌似没有发现。恰好前段时间写了一个 gRPC 的压测工具,其实曾经把该 APP 须要的外围性能也就是泛化调用实现了。 ...

November 29, 2021 · 1 min · jiezi

关于golang:Golang-程序启动过程

go run main.go 一个 Go 程序就启动了。然而这背地操作系统如何执行到 Go 代码的,Go 为了运行用户 main 函数,又做了什么?一 编译go build main.go咱们写的 go 代码都是编译成可执行文件去机器上间接执行的,在 linux 平台上是 ELF 格局的可执行文件,linux 能间接执行这个文件。 编译器:将 go 代码生成 .s 汇编代码,go 中应用的是 plan9 汇编汇编起:将汇编代码转成机器代码,即目标程序 .o 文件链接器:将多个 .o 文件合并链接失去最终可执行文件graph LR 0(写代码)--go程序--> 1(编译器)--汇编代码--> 2(汇编器)--.o目标程序-->3(链接器)--可执行文件-->4(完结)二 操作系统加载./main经上述几个步骤生成可执行文件后,二进制文件在被操作系统加载起来运行时会通过如下几个阶段: 从磁盘上把可执行程序读入内存;创立过程和主线程;为主线程调配栈空间;把由用户在命令行输出的参数拷贝到主线程的栈;把主线程放入操作系统的运行队列期待被调度执起来运行;START_THREAD(elf_ex, regs, elf_entry, bprm->p) 启动线程传入了 elf_entry 参数,这是程序的入口地址。 这个 elf_entry 被写在 elf 可执行文件的 header 中 $ readelf -h mainELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x45d430 Start of program headers: 64 (bytes into file) Start of section headers: 456 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 7 Size of section headers: 64 (bytes) Number of section headers: 25 Section header string table index: 3并且通过反编译 可执行文件,能够看到这个地址对应的就是 _rt0_amd64_linux。 ...

November 28, 2021 · 3 min · jiezi

关于golang:Go语言快速入门笔记01

语言个性部署简略: 可间接编译成机器码执行不依赖其余库间接运行即可部署动态类型语言:编译时即可查看出暗藏的问题语言层面的并发:天生反对并发,充分利用多核弱小的规范库: runtime系统调度机制高效的GC垃圾回收丰盛的规范库简略易学:25个关键字,反对内嵌C语法,面向对象,跨平台配置装置Mac下载地址:https://dl.google.com/go/go1.... 装置门路:/usr/local/go 配置环境变量: vi ~/.bash_profileexport GOPATH=$HOME/gosource ~/.bash_profile常见问题1.go.mod file not found in current directory or any parent directory 解决:go env -w GO111MODULE=auto 语法留神表达式结尾不倡议加分号导入多个包 import ( "fmt" "time")函数的花括号必须与函数名同行vim hello.gopackage mainimport "fmt"func main() { fmt.Println("Hello Go!")}编译并执行 go run hello.go编译 go build hello.go执行 ./hello变量 var申明一个变量(默认值是0) var a int申明一个变量,并初始化一个值 var b int = 100初始化时省去类型,通过值主动匹配数据类型(不举荐) var c = 100var cc = "abcd"fmt.Printf("cc=%s,cc=%T",cc,cc)//cc=abcd,cc=string省去var关键字,主动匹配(罕用) e := 100f := "abcd"备注:办法1.2.3能够在函数体外,申明全局变量;4只能在函数体内,申明局部变量 申明多行变量 var xx, yy int = 100, 200var mm, nn = 100, "abc"var ( cc int = 100 dd bool = true)fmt.Println("cc=",cc,"dd=",dd)常量 const常量是不容许批改的const a int = 100const ( BEIJING = 1 SHANGHAI = 2)iota:配合const应用,每行累加,第一行默认0const ( BEIJING = 10 * iota //0 SHANGHAI //10 SHENZHEN //20)const ( a, b = iota+1,iota+2//iota=0, a=1, b=2 c, d //iota=1, c=1, d=3 g, h = iota*2,iota*3//iota=3, g=6, h=9)函数根本函数模式 ...

November 28, 2021 · 5 min · jiezi

关于golang:Golang-关于-proto-文件的一点小思考

前言ProtoBuf 是什么? ProtoBuf 是一套接口描述语言(IDL),艰深的讲是一种数据表达方式,也能够称为数据交换格局。 咱们罕用的数据格式有 JSON 和 XML,为什么应用 ProtoBuf ?是因为它的传输快,为什么传输快?大家能够找下材料。应用 .proto 文件进行形容要序列化的数据结构,而后将写好 .proto 文件应用 protoc 就能够很容易编译成泛滥计算机语言的接口代码。 gRPC 是什么? gRPC 是开源的 RPC 框架,已反对支流的计算机语言,能够通过 ProtoBuf 进行定义接口,能够基于 ProtoBuf 进行数据传输。 两者尽管是一家,然而别离解决不同的问题,能够配合应用,也能够离开。 看一下的 gRPC helloworld 的 proto 文件是如何定义的? helloworld.protosyntax = "proto3";package helloworld;option go_package = "./;helloworld";// The greeting service definition.service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {}}// The request message containing the user's name.message HelloRequest { string name = 1;}// The response message containing the greetingsmessage HelloReply { string message = 1;}文件中定义了一个 service Greeter 和 rpc SayHello 办法。 ...

November 28, 2021 · 1 min · jiezi

关于golang:Golang-美化日志输出Ketty

Kettyketty 是一个Golang 开发的简略的日志丑化输入 Logger。 Githubhttps://github.com/anqiansong/ketty 装置$ go install github.com/anqiansong/ketty@latest疾速开始func main(){ console.Info(` { "name":"Hello Ketty", "description":"a color logger", "author":"anqiansong", "category":"console", "github":"https://github.com/anqiansong/ketty", "useage":[ "info", "debug" ] }`) console.Debug("Hello Ketty") console.Warn("Hello Ketty") console.Error(errors.New("error test"))}终端显示 Goland 显示 用法间接应用间接应用的 Console 实例反对一些默认配置项: 应用 frame.WithLineStyle 作为边框默认丑化日志func main(){ console.Info("Hello ketty, This is info log") console.Debug("Hello ketty, This debug log") console.Warn("Hello ketty, This warn log") console.Error(errors.New("Hello ketty,This is an error"))}初始化 // 替换默认的边框 plusStyle := text.WithPlusStyle() c := console.NewConsole(console.WithTextOption(plusStyle))Console 配置 c.DisableBorder() // 禁用边框 c.DisableColor() // 禁用色彩丑化打印 log // 输入 info 日志 c.Info("Hello Ketty, It's now %q", time.Now())边框款式预设款式WithLineStyle 默认款式 ...

November 26, 2021 · 2 min · jiezi

关于golang:Go-Web框架Gin源码结构解析

浏览本文之前,能够先读上一篇文章,对Web框架的外围组件有个理解。 源代码的目录构造以v1.7.4版本为例,Gin的源码目录构造如下图所示 +---.github| ISSUE_TEMPLATE.md| PULL_REQUEST_TEMPLATE.md| +---binding| binding.go| binding_msgpack_test.go| binding_nomsgpack.go| binding_test.go| default_validator.go| default_validator_test.go| form.go| form_mapping.go| form_mapping_benchmark_test.go| form_mapping_test.go| header.go| json.go| json_test.go| msgpack.go| msgpack_test.go| multipart_form_mapping.go| multipart_form_mapping_test.go| protobuf.go| query.go| uri.go| validate_test.go| xml.go| xml_test.go| yaml.go| yaml_test.go| +---examples| README.md| +---ginS| gins.go| README.md| +---internal| +---bytesconv| | bytesconv.go| | bytesconv_test.go| | | |---json| json.go| jsoniter.go| +---render| data.go| html.go| json.go| msgpack.go| protobuf.go| reader.go| reader_test.go| redirect.go| render.go| render_msgpack_test.go| render_test.go| text.go| xml.go| yaml.go| |---testdata| +---certificate| | cert.pem| | key.pem| | | +---protoexample| | test.pb.go| | test.proto| | | |---template| hello.tmpl| raw.tmpl| .gitignore| .travis.yml| auth.go| AUTHORS.md| auth_test.go| BENCHMARKS.md| benchmarks_test.go| CHANGELOG.md| codecov.yml| CODE_OF_CONDUCT.md| context.go| context_appengine.go| context_test.go| CONTRIBUTING.md| debug.go| debug_test.go| deprecated.go| deprecated_test.go| doc.go| errors.go| errors_1.13_test.go| errors_test.go| fs.go| gin.go| gin_integration_test.go| gin_test.go| githubapi_test.go| go.mod| go.sum| LICENSE| logger.go| logger_test.go| Makefile| middleware_test.go| mode.go| mode_test.go| path.go| path_test.go| README.md| recovery.go| recovery_test.go| response_writer.go| response_writer_test.go| result.txt| routergroup.go| routergroup_test.go| routes_test.go| test_helpers.go| tree.go| tree_test.go| utils.go| utils_test.go| version.go应用cloc工具对源码做一个扫描,总共代码行数不到1.2W。 ...

November 26, 2021 · 1 min · jiezi

关于golang:Go-和-Rust-我都要

大家好,我是张晋涛。 近期 Rust 社区/团队有些变动,所以再一次将 Rust 拉到大多数人眼前。 我最近看到很多小伙伴说的话: Rust 还值得学吗?社区是不是不稳固呀 Rust 和 Go 哪个好? Rust 还值得学吗? 这些问题如果有人来问我,那我的答复是: 小孩子才做抉择,我都要! 当然,对于 Rust 和 Go 的问题也不算新,比方之前的一条推文: 我在本篇中就来介绍下如何用 Go 调用 Rust。 当然,这篇中我基本上不会去比拟 Go 和 Rust 的性能,或者这种形式的性能之类的,Just for Fun FFI 和 BindingFFI (Foreign Function Interface) 翻译过去叫做内部函数接口(为了比较简单,下文中都将应用 FFI 指代)。最早来自于 Common Lisp 的标准,这是在 wiki 上写的,我并没有去考据。不过我所应用过的绝大多数语言中都有 FFI 的概念/术语存在,比方:Python、Ruby, Haskell、Go、Rust、LuaJIT 等。 FFI 的作用简略来说就是容许一种语言去调用另一种语言,有时候咱们也会用 Binding 来示意相似的能力。 在不同的语言中会有不同的实现,比方在 Go 中的 cgo , Python 中的 ctypes , Haskell 中的 CAPI (之前还有一个 ccall)等。我个人感觉 Haskell 中用 FFI 相比其余语言要更简略&不便的多,不过这不是本篇的重点就不开展了。 ...

November 26, 2021 · 2 min · jiezi

关于golang:API-编排的应用及痛点

作者:戴泽军 前言随着微服务架构成为业界支流,API 网关作为拜访微服务集群内所有 API 的惟一出入口,位置显得尤为重要。 集群内微服务性能拆分越来越细,对后端而言,模块在独立性、复用性、可维护性方面的劣势显而易见。但对前端而言,复杂性却随之而来。一个前端页面,往往须要从数个甚至数十个 API 中申请数据,而这些 API,很可能还存在如下异构个性:托管 host 不同、实现语言不同、调用形式不同。 面对这样的难题,API 网关的需要应运而生:对立进口、暗藏实现、安全控制、流量管制、负载平衡、权限管制、API 治理等等。这些问题及其解决方案将在后续的文章中一一介绍。本期咱们重点探讨 API 网关的另一个重要性能:API 编排。 API 编排的利用所谓 API 编排,就是通过 API 网关实现一种机制,能够灵便调用和组装后端原生 API,使前端可能依据业务需要,定制化页面所需的聚合 API。其位置和作用,可相较于“Shell 之于 *nix”。 一个典型的 API 编排利用案例如下: 图注:图中方框大小示意调用时数据量大小 能够看出,与后端微服务 API 以“高内聚”为指标不同,聚合 API 以业务需要为导向,通过简略组合已有的原生 API,在后端代理调用多个 API,并对输入数据进行从新剪裁组装。 API 编排的劣势与前端间接调用多个异构的后端 API 相比,聚合 API 具备很显著的劣势: 简化前端逻辑,一次 API 调用即可获取所有所需数据;缩小传输数据量,仅向前端发送须要展现的数据;灵便的动静组合扩大个性,后端只须要实现“原子 API”,把业务需要交给生产方去自助配置,组合扩大;异化调用办法,由 API 编排服务兼容异构实现的后端 API 的调用过程;对立的身份认证和权限治理;向前端暗藏第三方 API 的身份认证过程,由 API 编排服务兼容不同平台的 API 认证办法。API 编排的痛点面向没有编程根底的普通用户服务因为 API 编排具备“用户自助”的个性,注定了其用户“既是生产者又是消费者”。而任何网络平台的用户,都必须假设为“没有编程根底”,即面向没有编程教训的普通用户服务。 性能须要笼罩齐备的编程元素API 编排须要结构多个 API 调用,捕捉和剪裁输入数据,同时也可能存在分支和依据条件反复解决等需要。 咱们的编程启蒙老师肯定都讲过,编程无非就是程序+抉择+循环。可见,编程所需所有元素,在 API 编排中皆有需要。然而,在咱们的用户是没有编程根底的普通用户的状况下,如何让他们了解和形容要进行的操作,是另一个难题。 没有现成的编程语言可用站在程序员的角度,在各种高级编程语言百家争鸣的明天,形容和实现“ API 编排”需要的办法有千万种。 ...

November 25, 2021 · 1 min · jiezi

关于golang:gol内存逃逸

总结逃逸的指针变量自身也是调配在堆空间,故函数能够返回局部变量的地址。此时的局部变量相当于部分指针变量,逃逸时,指针变量自身也是调配在堆空间,所以能返回它的地址。栈空间的内存由编译器治理,调配开释速度很快。堆空间,由gc治理,频繁的gc会占用零碎较大的开销,stop the world逃逸剖析是编译器在动态编译时实现的。切片变量自身逃逸了,那它底层的data区域也会逃逸。即便切片长度很小。切片变量自身没逃逸,那个别状况它的data区域也在栈上,若长度太长,则data区域会调配到堆上,但切片变量自身还是在栈上。如何确定内存逃逸?go run -gcflags '-m -l' main.go留神:上述命令只在编译器接入判断是否逃逸处有输入。有时候栈空间比堆空间地址还小,不晓得为啥。 内存逃逸的例子func main() { a := 1 _ = a}// 无输入func main() { a := 1 fmt.Printf("%p\n", &a) fmt.Println(a) b := 2 fmt.Printf("%p\n", &b) fmt.Println(b) c := 3 fmt.Printf("%p\n", &c) fmt.Println(c) d := 4 fmt.Printf("%p\n", &d) fmt.Println(d)}// 输入./main.go:10:2: moved to heap: a./main.go:14:2: moved to heap: b./main.go:18:2: moved to heap: c./main.go:22:2: moved to heap: d./main.go:11:12: ... argument does not escape./main.go:12:13: ... argument does not escape./main.go:12:13: a escapes to heap./main.go:15:12: ... argument does not escape./main.go:16:13: ... argument does not escape./main.go:16:13: b escapes to heap./main.go:19:12: ... argument does not escape./main.go:20:13: ... argument does not escape./main.go:20:13: c escapes to heap./main.go:23:12: ... argument does not escape./main.go:24:13: ... argument does not escape./main.go:24:13: d escapes to heap0xc00001208010xc00001208820xc0000120a030xc0000120a84fmt.Printf函数abc赋值给interface{},造成逃逸,abc地址在堆空间,如图正增长,印证了在堆上。比照上面: ...

November 25, 2021 · 3 min · jiezi

关于golang:当前流行的Go-web框架比较以及Gin介绍

以后风行的Go语言web框架以下是截止到2021.10.03,GitHub上开源的Go Web框架状况。目前Gin是遥遥领先。 Project NameStarsForksOpen IssuesDescriptionLast Commitgin518945889443Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.2021-09-30 02:04:28beego27032531627beego is an open-source, high-performance web framework for the Go programming language.2021-09-18 15:08:26kit21360219247A standard library for microservices.2021-09-28 15:01:29echo20797184165High performance, minimalist Go web framework2021-09-26 15:56:43fasthttp16135133646Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http2021-10-01 11:38:31fiber1559078937⚡️ Express inspired web framework written in Go2021-10-02 01:54:34mux15202141324A powerful HTTP router and URL matcher for building Go web servers with 2021-09-14 12:12:19kratos14913300135A Go framework for microservices.2021-09-30 06:31:25httprouter13204127563A high performance HTTP request router that scales well2020-09-21 13:50:23revel124001402103A high productivity, full-stack web framework for the Go language.2020-07-12 05:57:36go-zero11533137234go-zero is a web and rpc framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.2021-10-02 10:16:59Web框架须要做什么咱们先思考下,一个残缺的Web开发框架须要做哪些事件 ...

November 25, 2021 · 1 min · jiezi

关于golang:zap-接收-gin-框架默认的日志

后面两篇曾经为大家介绍了golang中的日志如何应用,并在诸多日志框架库中抉择了zap作为咱们的日志框架,本篇将会解说: 如何联合当下支流的Web框架gin进行申请日志的打印对zap进行二次封装,注入trace信息,一遍咱们能够在业务中查问一次申请的所有残缺日志这里是前两篇的链接: https://www.yuque.com/jinsesi...https://www.yuque.com/jinsesi...1、gin 默认的中间件首先咱们来看一个最简略的 gin 我的项目: func main() { r := gin.Default() r.GET("/hello", func(c *gin.Context) { c.String("hello jianfan.com!") }) r.Run(}接下来咱们看一下gin.Default()的源码: func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery()) return engine}也就是咱们在应用gin.Default()的同时是用到了 gin 框架内的两个默认中间件Logger()和Recovery()。 其中Logger()是把 gin 框架自身的日志输入到规范输入(咱们本地开发调试时在终端输入的那些日志就是它的功绩),而Recovery()是在程序呈现 panic 的时候复原现场并写入 500 响应的。 2、基于 zap 的中间件gin框架反对用户自定义的middleware,咱们能够模拟Logger()和Recovery()的实现,应用咱们的日志库来接管 gin 框架默认输入的日志。这里以 zap 为例,咱们实现两个中间件如下: // GinLogger 接管gin框架默认的日志func GinLogger(logger *zap.Logger) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := c.Request.URL.RawQuery c.Next() cost := time.Since(start) logger.Info(path, zap.Int("status", c.Writer.Status()), zap.String("method", c.Request.Method), zap.String("path", path), zap.String("query", query), zap.String("ip", c.ClientIP()), zap.String("user-agent", c.Request.UserAgent()), zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()), zap.Duration("cost", cost), ) }}// GinRecovery recover掉我的项目可能呈现的panicfunc GinRecovery(logger *zap.Logger, stack bool) gin.HandlerFunc { return func(c *gin.Context) { defer func() { if err := recover(); err != nil { // Check for a broken connection, as it is not really a // condition that warrants a panic stack trace. var brokenPipe bool if ne, ok := err.(*net.OpError); ok { if se, ok := ne.Err.(*os.SyscallError); ok { if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { brokenPipe = true } } } httpRequest, _ := httputil.DumpRequest(c.Request, false) if brokenPipe { logger.Error(c.Request.URL.Path, zap.Any("error", err), zap.String("request", string(httpRequest)), ) // If the connection is dead, we can't write a status to it. c.Error(err.(error)) // nolint: errcheck c.Abort() return } if stack { logger.Error("[Recovery from panic]", zap.Any("error", err), zap.String("request", string(httpRequest)), zap.String("stack", string(debug.Stack())), ) } else { logger.Error("[Recovery from panic]", zap.Any("error", err), zap.String("request", string(httpRequest)), ) } c.AbortWithStatus(http.StatusInternalServerError) } }() c.Next() }}如果不想本人实现,能够应用 github 上有他人封装好的 https://github.com/gin-contrib/zap。 ...

November 24, 2021 · 4 min · jiezi

关于golang:go语言字符串不能修改

总结Go 语言中的字符串和其余高级语言(Java、C#)一样,默认是不可变的(immutable)。字符串不可变有很多益处: 如天生线程平安,大家应用的都是只读对象,毋庸加锁;再者,不便内存共享,而不用应用写时复制(Copy On Write)等技术;字符串 hash 值也只须要制作一份。批改字符串时,能够将字符串转换为 []byte 进行批改。[]byte 和 string 能够通过强制类型转换互转。字符串批改不能间接批改字符串变量的内容: var str string = "hello" str[0] = 'H' // Cannot assign to str[0] 编译(编辑器)报错切片的内容是可批改的,通过将string转换为[]byte切片,再批改切片内容,再转换回string var str string = "hello" strBytes := []byte(str) strBytes[0] = 'H' str = string(strBytes) fmt.Println(str)在实现了对 []byte 操作后,在第 9 行,应用 string() 将 []byte 转为字符串时,从新发明了一个新的字符串。最终str整体赋值为一个新的string 扩大字符串底层构造字符串底层构造定义在源码runtime包下的 string.go 文件中: // src/runtime/string.go type stringStruct struct { str unsafe.Pointer len int }str:一个指针,指向存储理论字符串的内存地址。len:字符串的长度。可应用len()函数获取这个值。留神,len存储理论的字节数,而非字符数。所以对于非单字节编码的字符,后果可能让人纳闷。对于字符串Hello,理论底层构造如下:

November 23, 2021 · 1 min · jiezi

关于golang:微服务治理之如何优雅应对突发流量洪峰

为什么须要降载微服务集群中,调用链路盘根错节,作为服务提供者须要有一种爱护本人的机制,避免调用方无脑调用压垮本人,保障本身服务的高可用。 最常见的爱护机制莫过于限流机制,应用限流器的前提是必须晓得本身的可能解决的最大并发数,个别在上线前通过压测来失去最大并发数,而且日常申请过程中每个接口的限流参数都不一样,同时零碎始终在一直的迭代其解决能力往往也会随之变动,每次上线前都须要进行压测而后调整限流参数变得十分繁琐。 那么有没有一种更加简洁的限流机制能实现最大限度的自我爱护呢? 什么是自适应降载自适应降载能十分智能的爱护服务本身,依据服务本身的零碎负载动静判断是否须要降载。 设计指标: 保证系统不被拖垮。在零碎稳固的前提下,放弃零碎的吞吐量。那么要害就在于如何掂量服务本身的负载呢? 判断高负载次要取决于两个指标: cpu 是否过载。最大并发数是否过载。以上两点同时满足时则阐明服务处于高负载状态,则进行自适应降载。 同时也应该留神高并发场景 cpu 负载、并发数往往稳定比拟大,从数据上咱们称这种景象为毛刺,毛刺景象可能会导致系统始终在频繁的进行主动降载操作,所以咱们个别获取一段时间内的指标均值来使指标更加平滑。实现上能够采纳精确的记录一段时间内的指标而后间接计算平均值,然而须要占用肯定的系统资源。 统计学上有一种算法:滑动均匀(exponential moving average),能够用来估算变量的部分均值,使得变量的更新与历史一段时间的历史取值无关,无需记录所有的历史局部变量就能够实现平均值估算,十分节俭贵重的服务器资源。 滑动均匀算法原理 参考这篇文章讲的十分分明。 变量 V 在 t 时刻记为 Vt,t 为变量 V 在 t 时刻的取值,即在不应用滑动均匀模型时 Vt=t,在应用滑动均匀模型后,Vt 的更新公式如下: Vt=⋅Vt−1+(1−)⋅t = 0 时 Vt = t = 0.9 时,大抵相当于过来 10 个 t 值的均匀 = 0.99 时,大抵相当于过来 100 个 t 值的均匀代码实现接下来咱们来看下 go-zero 自适应降载的代码实现。 core/load/adaptiveshedder.go 自适应降载接口定义: // 回调函数Promise interface { // 申请胜利时回调此函数 Pass() // 申请失败时回调此函数 Fail()}// 降载接口定义Shedder interface { // 降载查看 // 1. 容许调用,需手动执行 Promise.accept()/reject()上报理论执行工作构造 // 2. 回绝调用,将会间接返回err:服务过载谬误 ErrServiceOverloaded Allow() (Promise, error)}接口定义十分精简象征应用起来其实非常简单,对外裸露一个`Allow()(Promise,error)。 ...

November 23, 2021 · 4 min · jiezi

关于golang:Golang-中-defer-Close-的潜在风险

作为一名 Gopher,咱们很容易造成一个编程常规:每当有一个实现了 io.Closer 接口的对象 x 时,在失去对象并查看谬误之后,会立刻应用 defer x.Close() 以保障函数返回时 x 对象的敞开 。以下给出两个习用写法例子。 HTTP 申请resp, err := http.Get("https://golang.google.cn/")if err != nil { return err}defer resp.Body.Close()// The following code: handle resp拜访文件f, err := os.Open("/home/golangshare/gopher.txt")if err != nil { return err}defer f.Close()// The following code: handle f存在问题实际上,这种写法是存在潜在问题的。defer x.Close() 会疏忽它的返回值,但在执行 x.Close() 时,咱们并不能保障 x 肯定能失常敞开,万一它返回谬误应该怎么办?这种写法,会让程序有可能呈现十分难以排查的谬误。 那么,Close() 办法会返回什么谬误呢?在 POSIX 操作系统中,例如 Linux 或者 maxOS,敞开文件的 Close() 函数最终是调用了零碎办法 close(),咱们能够通过 man close 手册,查看 close() 可能会返回什么谬误 ERRORS The close() system call will fail if: [EBADF] fildes is not a valid, active file descriptor. [EINTR] Its execution was interrupted by a signal. [EIO] A previously-uncommitted write(2) encountered an input/output error.谬误 EBADF 示意有效文件描述符 fd,与本文中的状况无关;EINTR 是指的 Unix 信号打断;那么本文中可能存在的谬误是 EIO。 ...

November 22, 2021 · 2 min · jiezi

关于golang:Golang-协程与调度器原理

思考从容器上该如何设置 GOMAXPROCS 大小引发,这个数字设置多少正当,其到底限度了什么,cpu 核数,零碎线程数还是协程数?背景Go 语言能够说为并发而生。Go 从语言级别反对并发,通过轻量级协程 Goroutine 来实现程序并发运行,go关键字的弱小与简洁是其它语言不可及的,接下来让咱们一起来摸索 Golang 中 Goroutine 与协程调度器设计的一些原理吧。 Go 协程概念过程: 操作系统调配系统资源(cpu 工夫片,内存等)的最小单位 线程:轻量级过程,是操作系统调度的最小单位 协程:轻量级线程,协程的调度由程序控制 怎么了解过程,线程的两个最小单位如何了解?在晚期面向过程设计的计算机构造中,过程就是操作系统调配系统资源与操作系统调度的最小单位 但在古代的计算构造中,过程降级为线程的容器,多个线程共享一个过程内的系统资源,cpu 执行(调度)对象是线程 轻量级过程与轻量级线程如何了解轻量级过程:如下图各个过程领有独立的虚拟内存空间,外面的资源包含 栈,代码,数据,堆... 而线程领有独立的栈,然而共享过程全副的资源。在 linux 的实现中,过程与线程的底层数据结构是统一的,只是同一过程下线程会共享资源。 轻量级线程:线程栈大小固定 8 M,协程栈:2 KB ,动静增长。一对线程里对应多个协程,能够缩小线程的数量 协程绝对线程有什么劣势轻量级 (MB vs KB)切换代价低 (调度由程序控制,不须要进入内核空间。须要保留上下文个别少一些)切换频率低,协程合作式调度,线程调度由操作系统管制,须要保障公平性,当线程数量一多,切换频率绝对比拟高协程调度器在 Golang 中,goroutine 调度是由 Golang 运行时(runtime)负责的,不须要程序员编写代码时关注协程的调度。 GM 模型goroutine 的调度其实是一个生产者-消费者模型。 生产者:程序起 goroutine(G) 消费者:零碎线程(M)去生产(执行)goroutine 天然的,在生产者与消费者两头还须要有一个队列来暂存没有生产过的 goroutine。在 Go 1.1 版本,用的就是这种模型。 GM 模型问题 M 是并发的,每次拜访这个全局队列须要全局锁,锁竞争比较严重疏忽了 G 之间的关系,例如,M1 执行 G1 时,G1 创立了 G2,为了执行 G2 很有可能放到 M2 中执行。而 G1,G2 是相干的,缓存大概率是比拟靠近的,这样会导致性能降落每一个 M 都调配一块缓存 MCache,比拟节约GOMAXPROCS:在这个版本代表了最多同时反对 GOMAXPROCS 个沉闷的线程。 ...

November 22, 2021 · 1 min · jiezi

关于golang:Go语言如何高效的进行字符串拼接6种方式进行对比分析

原文链接:Go语言如何高效的进行字符串拼接(6种形式进行比照剖析) 前言哈喽,大家好,我是asong 日常业务开发中离不开字符串的拼接操作,不同语言的字符串实现形式都不同,在Go语言中就提供了6种形式进行字符串拼接,那这几种拼接形式该如何抉择呢?应用那个更高效呢?本文咱们就一起来剖析一下。 本文应用Go语言版本:1.17.1 string类型咱们首先来理解一下Go语言中string类型的构造定义,先来看一下官网定义: // string is the set of all strings of 8-bit bytes, conventionally but not// necessarily representing UTF-8-encoded text. A string may be empty, but// not nil. Values of string type are immutable.type string stringstring是一个8位字节的汇合,通常但不肯定代表UTF-8编码的文本。string能够为空,然而不能为nil。string的值是不能扭转的。 string类型实质也是一个构造体,定义如下: type stringStruct struct { str unsafe.Pointer len int}stringStruct和slice还是很类似的,str指针指向的是某个数组的首地址,len代表的就是数组长度。怎么和slice这么类似,底层指向的也是数组,是什么数组呢?咱们看看他在实例化时调用的办法: //go:nosplitfunc gostringnocopy(str *byte) string { ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)} s := *(*string)(unsafe.Pointer(&ss)) return s}入参是一个byte类型的指针,从这咱们能够看出string类型底层是一个byte类型的数组,所以咱们能够画出这样一个图片: string类型实质上就是一个byte类型的数组,在Go语言中string类型被设计为不可变的,不仅是在Go语言,其余语言中string类型也是被设计为不可变的,这样的益处就是:在并发场景下,咱们能够在不加锁的管制下,屡次应用同一字符串,在保障高效共享的状况下而不必放心平安问题。 string类型尽管是不能更改的,然而能够被替换,因为stringStruct中的str指针是能够扭转的,只是指针指向的内容是不能够扭转的,也就说每一个更改字符串,就须要重新分配一次内存,之前调配的空间会被gc回收。 对于string类型的知识点就形容这么多,不便咱们前面剖析字符串拼接。 字符串拼接的6种形式及原理原生拼接形式"+"Go语言原生反对应用+操作符间接对两个字符串进行拼接,应用例子如下: ...

November 22, 2021 · 3 min · jiezi

关于golang:Go语言中结构体打Tag是什么意思

原文链接:Go语言中构造体打Tag是什么意思? 前言哈喽,大家好,我是asong。明天想与大家分享Go语言中构造体标签是怎么应用的,以及怎么定制本人的构造体标签解析。 大多数初学者在看公司的我的项目代码时,看到的一些构造体定义会是这样的: type Location struct { Longitude float32 `json:"lon,omitempty"` Latitude float32 `json:"lat,omitempty"`}字段前面会有一个标签,这个标签有什么用呢? 下面的例子中,标签json:"lon,omitempty"代表的意思是构造体字段的值编码为json对象时,每一个导出字段变成该对象的一个成员,这个成员的名字为lon或者lat,并且当字段是空值时,不导出该字段;总结就是lon、lat是重命名成员的名字,omitempty用来决定成员是否导出。 看到这里,有一些敌人可能会好奇,这个你是怎么晓得这样应用的呢?我能够轻易写标签吗? 接下来咱们就一点点来揭秘,开车!!! 什么是标签Go语言提供了可通过反射发现的的构造体标签,这些在规范库json/xml中失去了宽泛的应用,orm框架也反对了构造体标签,下面那个例子的应用就是因为encoding/json反对了构造体标签,不过他有本人的标签规定;然而他们都有一个总体规定,这个规定是不能更改的,具体格局如下: `key1:"value1" key2:"value2" key3:"value3"...` // 键值对用空格分隔构造体标签能够有多个键值对,键与值要用冒号分隔,值要应用双引号括起来,多个键值对之间要应用一个空格分隔,千万不要应用逗号!!! 如果咱们想要在一个值中传递多个信息怎么办?不同库中实现的是不一样的,在encoding/json中,多值应用逗号分隔: `json:"lon,omitempty"`在gorm中,多值应用分号分隔: `gorm:"column:id;primaryKey"具体应用什么符号分隔须要大家要看各自库的文档获取。 构造体标签是在编译阶段就和成员进行关联的,以字符串的模式进行关联,在运行阶段能够通过反射读取进去。 当初大家曾经晓得什么是构造体标签了,规定还是很标准的,然而很容易出错,因为Go语言在编译阶段并不会对其格局做非法键值对的查看,这样咱们不小心写错了,就很难被发现,不过咱们有go vet工具做查看,具体应用来看一个例子: type User struct { Name string `abc def ghk` Age uint16 `123: 232`}func main() {}而后执行go vet main.go,得出执行后果: # command-line-argumentsgo_vet_tag/main.go:4:2: struct field tag `abc def ghk` not compatible with reflect.StructTag.Get: bad syntax for struct tag pairgo_vet_tag/main.go:5:2: struct field tag `123: 232` not compatible with reflect.StructTag.Get: bad syntax for struct tag valuebad syntax for struct tag pair通知咱们键值对语法错误,bad syntax for struct tag value值语法错误。 ...

November 22, 2021 · 2 min · jiezi

关于golang:如何通过抓包来查看Kubernetes-API流量

当咱们通过kubectl来查看、批改Kubernetes资源时,有没有想过前面的接口到底是怎么的?有没有方法探查这些交互数据呢? Kuberenetes客户端和服务端交互的接口,是基于http协定的。所以只须要可能捕获并解析https流量,咱们就能看到kubernetes的API流量。 然而因为kubenetes应用了客户端私钥来实现对客户端的认证,所以抓包配置要简单一点。具体是如下的构造: 如果想理解更多Kubernetes证书的常识,能够看下这篇Kubernetes证书解析的文章 从kubeconfig中提取出客户端证书和私钥kubeconfig中蕴含了客户端的证书和私钥,咱们首先要把它们提取进去: # 提取出客户端证书grep client-certificate-data ~/.kube/config | \ awk '{ print $2 }' | \ base64 --decode > client-cert.pem# 提取出客户端私钥grep client-key-data ~/.kube/config | \ awk '{ print $2 }' | \ base64 --decode > client-key.pem# 提取出服务端CA证书grep certificate-authority-data ~/.kube/config | \ awk '{ print $2 }' | \ base64 --decode > cluster-ca-cert.pem参考自Reddit 配置Charles代理软件从第一张图能够看出,代理软件的作用有两个:一是接管https流量并转发,二是转发到kubernetes apiserver的时候,应用指定的客户端私钥。 首先配置Charles,让他拦挡所有的https流量: 而后配置客户端私钥,即对于发送到apiserver的申请,对立应用指定的客户端私钥进行认证: 配置kubectl须要抓包kubectl的流量,须要两个条件:1. kubectl应用Charles作为代理,2. kubectl须要信赖Charles的证书。 # Charles的代理端口是8888,设置https_proxy环境变量,让kubectl应用Charles代理$ export https_proxy=http://127.0.0.1:8888/# insecure-skip-tls-verify示意不校验服务端证书$ kubectl --insecure-skip-tls-verify get podNAME READY STATUS RESTARTS AGEsc-b-7f5dfb694b-xtfrz 2/2 Running 0 2d20h咱们就能够看到get pod的网络申请了: ...

November 21, 2021 · 2 min · jiezi

关于golang:sockfwd-一个数据转发的小工具

最近在看containerd的代码,上手试的时候才发现它监听的是unix socket,没法从内部拜访containerd。而我要验证的是从远端能不能拜访containerd、治理containerd的容器,所以须要一个从远端拜访unix socket的工具。 网上搜了一圈,没有现成的实现,就本人写了 sockfwd。 用法Usage: sockfwd [flags]Flags: -d, --destination string 目标地址,即要转发到的地址 -s, --source string 源地址,即接管申请的地址 -q, --quiet 静默模式例子将本地的containerd实例裸露到网络上: ./sockfwd -s tcp://127.0.0.1:8090 -d unix:///var/run/containerd.sock 将本地的127.0.0.1:8080端口裸露到0.0.0.0:8090端口上: ./sockfwd -s tcp://127.0.0.1:8090 -d unix://127.0.0.1:8090 将本地的服务裸露到网络上,须要分外留神是否有安全隐患! 其余碎碎念最近在写golang,发现如果仅仅是解决数据面的话,golang提供的goroute再加channel就可能很优雅地解决数据转发,比方这篇文章写的sockfwd。 然而如果波及管控面,比方简单的状态治理,信息跨线程/goroute同步,那么channel的形象能力还是不够的,须要写很多额定代码。 后续打算能够加上反对tls认证来更加平安地转发数据。

November 21, 2021 · 1 min · jiezi

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

download:极客工夫-Go进阶训练营|全新降级第4期allow_system_table_mods Allows modifications of the structure of system tables. 容许修改零碎表的结构。application_name Sets the application name to be reported in statistics and logs. 设置要在统计和日志中报告的应用程序名称。archive_command Sets the shell command that will be called to archive a WAL file. 设置将调用的命令来归档一个文件。archive_mode Allows archiving of WAL files using archive_command. 容许使用archive_command WAL文件归档。archive_timeout Forces a switch to the next xlog file if a new file has not been started within N seconds. 强制切换到下一个文件,如果一个新Xlog文件尚未在N秒开始。array_nulls Enable input of NULL elements in arrays. 启用数组中null元素的输出。authentication_timeout Sets the maximum allowed time to complete client authentication. 设置实现客户端身份考据的最大容许工夫。autovacuum Starts the autovacuum subprocess. 开始autovacuum子。autovacuum_analyze_scale_factor Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples. 元组的插入、更新或删除数,分析作为reltuples分数之前。autovacuum_analyze_threshold Minimum number of tuple inserts, updates, or deletes prior to analyze. 在分析之前插入、更新或删除的最小元组数。autovacuum_freeze_max_age Age at which to autovacuum a table to prevent transaction ID wraparound. 年龄在autovacuum表以防止事务ID的概括。autovacuum_max_workers Sets the maximum number of simultaneously running autovacuum worker processes. 组同时运行autovacuum工人最大过程数。autovacuum_naptime Time to sleep between autovacuum runs. 睡觉的工夫autovacuum之间运行。autovacuum_vacuum_cost_delay Vacuum cost delay in milliseconds, for autovacuum. 真空成本提早毫秒,对于autovacuum。autovacuum_vacuum_cost_limit Vacuum cost amount available before napping, for autovacuum. 真空成本金额可用午睡前后,为autovacuum。autovacuum_vacuum_scale_factor Number of tuple updates or deletes prior to vacuum as a fraction of reltuples. 一些元组更新或删除reltuples真空作为一部分之前。autovacuum_vacuum_threshold Minimum number of tuple updates or deletes prior to vacuum. 在真空之前元组更新或删除的最小数目。backslash_quote Sets whether "\'" is allowed in string literals. 设置字符串文本中是否容许“\”。bgwriter_delay Background writer sleep time between rounds. 背景作家轮间睡眠工夫。bgwriter_lru_maxpages Background writer maximum number of LRU pages to flush per round. 背景的作家最大数量的LRU页面刷新每轮。bgwriter_lru_multiplier Multiple of the average buffer usage to free per round. 平均缓冲区使用量的倍数为每轮收费。block_size Shows the size of a disk block. 浮现磁盘块的大小。bonjour Enables advertising the server via Bonjour. 使广告服务器通过卓悦。bonjour_name Sets the Bonjour service name. 集的Bonjour服务名称。bytea_output Sets the output format for bytea. 集bytea输入格局。check_function_bodies Check function bodies during CREATE FUNCTION. 在创建函数期间查看函数体。checkpoint_completion_target Time spent flushing dirty buffers during checkpoint, as fraction of checkpoint interval. 在查看点中清除脏缓冲区的工夫,作为检查点间隔的一部分。checkpoint_segments Sets the maximum distance in log segments between automatic WAL checkpoints. 设置主动检查点之间的日志段的最大距离。checkpoint_timeout Sets the maximum time between automatic WAL checkpoints. 设置主动检查点之间的最大工夫。checkpoint_warning Enables warnings if checkpoint segments are filled more frequently than this. 如果检查点段填充比此更频繁,则启用警告。client_encoding Sets the client's character set encoding. 设置客户端的字符集编码。client_min_messages Sets the message levels that are sent to the client. 设置发送给客户机的消息级别。commit_delay Sets the delay in microseconds between transaction commit and flushing WAL to disk. 在事务提交和刷新到磁盘之间设置提早微秒。commit_siblings Sets the minimum concurrent open transactions before performing commit_delay. 设置最小并发公开交易前执行commit_delay。config_file Sets the server's main configuration file. 设置服务器的主配置文件。constraint_exclusion Enables the planner to use constraints to optimize queries. 使布局人员能够使用束缚来优化查问。cpu_index_tuple_cost Sets the planner's estimate of the cost of processing each index entry during an index scan. 在索引扫描期间设置计划者对处理每个索引项的成本的估计值。cpu_operator_cost Sets the planner's estimate of the cost of processing each operator or function call. 设置计划者对每个操作员或函数调用途理成本的估计值。cpu_tuple_cost Sets the planner's estimate of the cost of processing each tuple (row). 设置计划程序处理每个元组(行)的成本的估计值。cursor_tuple_fraction Sets the planner's estimate of the fraction of a cursor's rows that will be retrieved. 设置要检索的游标行的小数部分的计划者的估计值。data_directory Sets the server's data directory. 设置服务器的数据目录。DateStyle Sets the display format for date and time values. 设置日期和工夫值的浮现格局。db_user_namespace Enables per-database user names. 启用每个数据库用户名。deadlock_timeout Sets the time to wait on a lock before checking for deadlock. 在查看死锁之前设置等待锁的工夫。debug_assertions Turns on various assertion checks. 打开各种断言查看。debug_pretty_print Indents parse and plan tree displays. 缩进的解析和计划树浮现。debug_print_parse Logs each query's parse tree. 记录每个查问的解析树。debug_print_plan Logs each query's execution plan. 记录每个查问的执行计划。debug_print_rewritten Logs each query's rewritten parse tree. 记录每个查问重写的解析树。default_statistics_target Sets the default statistics target. 设置默认统计目标。default_tablespace Sets the default tablespace to create tables and indexes in. 设置默认表空间以创建表和索引。default_text_search_config Sets default text search configuration. 设置默认文本搜寻配置。default_transaction_deferrable Sets the default deferrable status of new transactions. 套新事务的默认提早状态。default_transaction_isolation Sets the transaction isolation level of each new transaction. 设置每个新事务的事务隔离级别。default_transaction_read_only Sets the default read-only status of new transactions. 设置新事务的默认只读状态。default_with_oids Create new tables with OIDs by default. 创建新表时默认。dynamic_library_path Sets the path for dynamically loadable modules. 设置动静可加载模块的路径。effective_cache_size Sets the planner's assumption about the size of the disk cache. 设置布局程序对于磁盘缓存大小的假设。effective_io_concurrency Number of simultaneous requests that can be handled efficiently by the disk subsystem. 磁盘子系统可能高效处理的同时请求数。enable_bitmapscan Enables the planner's use of bitmap-scan plans. 使布局人员使用位图扫描计划。enable_hashagg Enables the planner's use of hashed aggregation plans. 使计划使用哈希聚合计划。enable_hashjoin Enables the planner's use of hash join plans. 使计划人员使用哈希连接计划。enable_indexonlyscan Enables the planner's use of index-only-scan plans. 使布局人员只使用索引扫描计划。enable_indexscan Enables the planner's use of index-scan plans. 容许计划人员使用索引扫描计划。enable_material Enables the planner's use of materialization. 容许策划者使用物化。enable_mergejoin Enables the planner's use of merge join plans. 使计划人员使用合并联接计划。enable_nestloop Enables the planner's use of nested-loop join plans. 使策划者能够使用嵌套循环连接计划。enable_seqscan Enables the planner's use of sequential-scan plans. 使布局人员使用次序扫描计划。enable_sort Enables the planner's use of explicit sort steps. 使布局人员使用显式排序步骤。enable_tidscan Enables the planner's use of TID scan plans. 使计划使用TID扫描计划。escape_string_warning Warn about backslash escapes in ordinary string literals. 警告在一般字符串中的反斜杠。event_source Sets the application name used to identify PostgreSQL messages in the event log. 设置用于必定在事件日志消息的应用程序名称PostgreSQL。exit_on_error Terminate session on any error. 终止任何谬误的会话。external_pid_file Writes the postmaster PID to the specified file. 将邮政局长PID写入指定的文件。extra_float_digits Sets the number of digits displayed for floating-point values. 设置浮现浮点值的位数。from_collapse_limit Sets the FROM-list size beyond which subqueries are not collapsed. 设置从列表的大小超过该子查问不倒塌。fsync Forces synchronization of updates to disk. 强制更新到磁盘的同步。full_page_writes Writes full pages to WAL when first modified after a checkpoint. 在检查点第一次修改后写入完整的页面。geqo Enables genetic query optimization. 启用遗传查问优化。geqo_effort GEQO: effort is used to set the default for other GEQO parameters. geqo:致力是用来为其余geqo参数设置默认。geqo_generations GEQO: number of iterations of the algorithm. geqo:算法的迭代次数。geqo_pool_size GEQO: number of individuals in the population. geqo:群体中的个体数。geqo_seed GEQO: seed for random path selection. geqo:种子随机路径抉择。geqo_selection_bias GEQO: selective pressure within the population. geqo:在人口压力。geqo_threshold Sets the threshold of FROM items beyond which GEQO is used. 设置阈值的物品之外,geqo使用。gin_fuzzy_search_limit Sets the maximum allowed result for exact search by GIN. 设置杜松子酒精确搜寻的最大容许后果。hba_file Sets the server's "hba" configuration file. 设置服务器的HBA配置文件。hot_standby Allows connections and queries during recovery. 容许复原期间的连接和查问。hot_standby_feedback Allows feedback from a hot standby to the primary that will avoid query conflicts. 容许来自热备份的反馈到主,避免查问冲突。ident_file Sets the server's "ident" configuration file. 设置服务器的“识别”配置文件。ignore_system_indexes Disables reading from system indexes. 禁用零碎索引读取。integer_datetimes Datetimes are integer based. 日期是基于整数。IntervalStyle Sets the display format for interval values. 设置区间值的浮现格局。 ...

November 20, 2021 · 5 min · jiezi

关于golang:跟着老猫来搞GO容器1

后期回顾后面的一章次要和大家分享了GO语言的函数的定义,以及GO语言中的指针的简略用法,那么本章,老猫就和大家一起来学习一下GO语言中的容器。 数组数组的定义说到容器,大家有编程教训的必定第一个想到的就是数组了,当然也有编程教训的小伙伴会感觉数组并不是容器。然而无论如何,说到数组其实它就是存储和组织数据的一种形式而已,大家就不要太过纠结叫法了。 咱们间接上数组定义的例子,具体如下: var arr1 [5]int //定义一个长度为5的默认类型arr2:=[3]int{1,2,3} //定义一个数组,并且指定长度为3arr3:=[...]int{1,2,3,4,5,6} //定义一个数组,具体的长度交给编译器来计算var grid [4][5] bool //定义一个四行五列的二维数组fmt.Println(arr1,arr2,arr3,grid)下面的例子输入的后果如下 [0 0 0 0 0] [1 2 3] [1 2 3 4 5 6] [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]大家能够总结一下,其实数组有这么几个特点 在写法上,其实也是和其余编程语言是相同的,其定义的数组的长度写在变量类型的后面数组中所存储的内容必然是同一类型的数组的遍历那么咱们如何遍历获取数组中的数据呢?其实看过老猫之前文章的小伙伴应该知道能够用for循环来遍历获取,其中一种大家比拟容易想到的形式如下(咱们以遍历下面的arr3为例) for i:=0;i<len(arr3);i++ { fmt.Println(arr3[i])}这种形式呢,咱们当然是能够获取的。接下来老猫其实还想和大家分享另外一种形式,采纳range关键字的形式 //i示意的是数据在数组中的地位下标,v示意理论的值for i,v :=range arr3 { fmt.Println(i,v)}//那么如果咱们只想要value值呢,回顾一下老猫之前所说的就能够知道,咱们能够用_的形式进行对i省略for _,v :=range arr3 { fmt.Println(v)}//如果咱们只有地位下标,那么咱们如上来写即可for i:=range arr3 { fmt.Println(i)}大家感觉上述两种形式哪种形式会比拟优雅?不言而喻是后者了,意义明确而且好看。 go语言中数组是值传递的另外和大家同步一点是数组作为参数也是值传递。还是沿用之前的咱们从新定义一个新的函数如下: func printArray(arr [5]int){ for i,v:=range arr { println(i,v) }}那么咱们在main函数中进行相干调用(为了演示编译谬误,老猫这里用图片) ...

November 19, 2021 · 2 min · jiezi

关于golang:跟着老猫来搞GO基础进阶

回顾一下上一篇博客,次要是和大家分享了GO语言的根底语法,其中蕴含变量定义,根本类型,条件语句,循环语句。那本篇呢就开始和大家同步一下GO语言根底的进阶。 函数的定义上次其实在很多的DEMO中曾经写进去一些函数了,然而没有讲清楚其函数定义。接下来咱们同样地要举例说明一下,间接看代码。 func calculate(a,b int, op string) int { switch op { case "+": return a + b case "-": return a - b case "*": return a * b case "/": return a / b default: panic("unsupported op") }}以上是一个比较简单的计算两个整数加减乘除运算的一个函数,首先咱们能够看到的是函数的定义其实也是遵循着变量的定义形式,咱们先定义函数的名称,而后才是函数的返回值。当然函数中的参数定义也是如此。 除此以外,其实GO语言绝对于其余语言来说有一个比拟骚的操作,就是他能够存在多个返回值。例如上面咱们写一个除法的例子,就是大家小学就学过的除不尽的时候存在余数的状况。上面咱们来看一个函数。 func div(a int, b int) (int,int){ return a / b, a % b}大家看到下面这个返回值有什么感想,其实这最终的两个返回值是没有体现任何业务意义的,咱们无奈辨别最终返回的后果到底是干什么用的。当然GO语言其实也发现了这个弊病,所以呢,咱们的返回值的名称也是能够定义的,具体如下,咱们命名除法失去的商为q,余数为r,那么咱们改良之后就失去如下: func div(a int, b int) (q ,r int){ return a / b, a % b}如果这样的话咱们main调用失去后果就能够这么获取 ...

November 19, 2021 · 2 min · jiezi

关于golang:跟着老猫来搞GO基础语法

上次博客中,老猫曾经和大家同步了如何搭建相干的GO语言的开发环境,置信在车上的小伙伴应该都曾经搞定了环境了。那么本篇开始,咱们就来相熟GO语言的根底语法。本篇搞定之后,其实期待大家能够和老猫一样,可能写出一些比较简单的代码片段。 变量定义变量的定义其实也是比较简单的,次要就是利用var关键字+变量的名称+变量的类型。例子如下: func variableDefinition() { var a int var s string fmt.Printf("%d %q\n",a,s)}大家能够比拟容易地发现go语言的定义形式比拟特地,其变量名称是放在类型之前的。其实集体认为这也是和人的思考形式有关系,有的人在写变量的时候先想到的是名称再想到是类型,而有些人先想到是类型,而后是名称。这里须要留神的是,如果咱们不赋予相干的初始值的时候,go语言其实会自带初始化的值,以上的程序通过main函数执行结束之后,就会输入 0 ""大家能够试着去写一下,而后运行一下,至于其中的占位符,以及为什么这么写,这个大家能够查阅一下相干的手册。这些属于死常识。 再看上面比拟骚的定义,针对多个变量同时赋值的时候,能够这样写 func variableInitialValue(){ var a,b int = 3,4 var s string = "abc" fmt.Println(a,b,s)}演变的再再骚一些,其实能够间接连变量的名称都不写,不同类型的变量能够写在同一行,GO语言会自动识别变量的类型是什么。 func variableDeduction(){ var a,b,c,d = 3,4,"666",true fmt.Println(a,b,c,d)}在GO语法外面咱们甚至连var都不写,间接用:=的形式去初始化变量,具体如下。 func variableShorter(){ a,b,c,d := 3,4,"666",true fmt.Println(a,b,c,d)}然而这种写法只可能在办法体内去写,如果在存在包内作用变量,那么此时就不能这么写必须还是老老实实的用var关键字,或者用var关键字外加括号的模式。代码如下: var ( aa = 1 bb = "ktdaddy" cc = true)func variableDefinition() { var a int var s string fmt.Printf("%d %q\n",a,s)}然而以上这些定义有个留神点,无论如何定义,定义好的变量必须得在后续中用到,否则会报语法错误。 以上差不多是所有GO的变量的定义了,咱们来做一下总结。应用var关键字定义变量 变量定义var a,b,c bool变量初始化var a,b string = "hello","world"变量能够定义在函数内,也能够定义在包内当然还以用var()集中来进行变量定义。编译器能够主动决定类型 var a,b,c,d = 3,4,"666",true函数内能够应用标记来进行变量定义 a,b,c,d := 3,4,"666",true,然而无奈在包内应用,只能在函数内根本数据类型下面咱们介绍了一下变量的定义,然而咱们的变量又有哪些内建变量类型呢?目前次要分为以下大类。 ...

November 19, 2021 · 2 min · jiezi

关于golang:跟着老猫来搞GO环境搭建

老猫的GO学习系列博客曾经正式发车了,置信大家以前学习一门编程语言的时候也有教训,咱们个别都是从环境开始,在此呢,大家也跟着老猫从最开始的搭建环境开始。 GO语言的装置首先呢,咱们开始须要下载GO语言的安装包。GO国外的官网地址是https://golang.org/,当然这个仅限于有条件的小伙伴去官网下载了。咱们个别下载呢都有所限度,不过没关系,在国内其实也有对应的网站为https://golang.google.cn/。还有一个网站中也能够下载,差不多是一个GO语言的学习社区,地址为https://studygolang.com/dl。比拟举荐后者,相干的中文英文文档也是比拟全的。拜访https://studygolang.com/dl关上是这样的: 大家依据本人的环境,抉择对应的安装包一步步装置即可。这个太简略了,就不开展了。 装置结束之后,大家在命令行运行go version命令失去相干的版本信息,那么就装置实现了。老猫因为之前就曾经装置过了,目前不是那个最新的版本,所以装置结束之后的版本信息如下。 国内镜像的配置对于go环境搭建的过程中比拟重要的一点是镜像的配置,大家输出命令go env 能够看到相干go 语言的环境的一些配置。 goproxy设置老猫以后的计算机环境是windows,所以看到的信息如上,下面有一个比拟重要的属性信息叫做goproxy,老猫目前的设置是https://goproxy.cn,direct,大家装置结束之后默认的地址应该是https://proxy/golang.org,direct。那么这个配置到底是做什么的呢?其实很简略,能够类比maven,这个其实也是一个依赖,配置这个代理信息之后,就会从近程的仓库拉取相干的go所须要依赖。前面的direct示意如果前者不能提供所须要的依赖那么咱们能够从新从其余第三方获取依赖,比方配置成某github的依赖。 大家如果网络上没有条件的话,配置成默认的地址应该是无奈拉取相干的依赖的,所以在此呢,最好配置成咱们国内的镜像。 老猫配置国内镜像其实次要参考这个网址:https://goproxy.cn/,关上之后,下面有具体的设置命名的,大家照着下面设置即可,当然这里有个坑点就是咱们的go的版本号必须是1.13以上,当然如果是下载的最新安装包的小伙伴其实是没有这个问题的。 GO111MODULE设置下面的截图中咱们其实还看到一个比拟重要的属性,就是GO111MODULE,老猫查问了其余的一些材料。 在go1.11版本以前,想要对GO语言进行包治理,只能依赖第三方的库进行实现,比方Vendor,GoDep等等。然而在这之后,咱们就能够依据这个开关来实现包治理。 GO111MODULE这个开启或者敞开次要有三个值能够抉择:off、on 、auto,默认值是个“”,其实也就是auto。 GO111MODULE=off 无模块反对,go会从GOPATH和vendor文件寻找包。GO111MODULE=on 模块反对,go会疏忽gopath和vendor文件夹,只依据go.mod下载依赖。GO111MODULE=auto在$GOPATH/SRC里面且根目录有go.mod文件时开启模块反对。以上这些形容其实听下来感觉是只知其一;不知其二的样子,在此其实也不必过多去纠结,因为在前面深刻的过程中,咱们就会缓缓体会了。当然后续老猫在和大家分享“依赖治理”的时候会和大家深刻地去探讨一下。在此呢,咱们将其属性设置成on。设置的命令下面也有。比拟须要留神的是,在设置的时候大家须要设置成小写的on才行,不要手误操作错了。 开发工具配置下面介绍了相干go环境的配置其实到此曾经OK了,那么上面咱们就能够筛选一个比拟趁手的工具开始配置完之后撸代码了。其实go相干的开发工具有很多,比方vi,emacs,idea,eclipse,vscode,sublime..+go插件。当然IDE系列的也有goland的,大家也能够去官网进行下载。老猫接下来会其中一种开发工具,IDEA+GO插件的形式,因为老猫是JAVA后端,用惯了IDEA,所以在此也就先介绍这款配置。当然其余开发工具的相干配置,大家能够自行去度娘或者谷歌去找一下。 idea插件举荐第一个插件当然是go插件,具体如下: 这是老猫本地的环境,曾经装置结束了。 另外一个插件是File Watcher,大家能够自行像下面那样搜寻之后进行install。这个工具其实是一个主动格式化的工具,当咱们保留文件的时候就会依照GO语言的规范进行格式化了。 装置结束之后咱们重启IDEA,而后建设一个GO我的项目,来写一个GO版本的HELLO WORLD。具体如下 咱们须要建设一个GO MODULE的我的项目,此处有个主见点就是proxy的时候,它默认会是default,咱们将其改成https://goproxy.cn,direct即可,当然这个门路就是咱们下面所配置的代理。因为我的项目临时不波及SQL,所以咱们间接下一步并且取名实现即可。 大家能够看一下老猫的我的项目。 留神点,这里进行new文件的时候,抉择simpleApplication类型的,点击运行,砸门的helloworld就显示在管制台上了。 下面老猫说的file watcher插件目前是不失效的,其实咱们还要进行设置一下,具体设置如下。 首先咱们须要将该设置去除。 而后咱们从新搜寻file watcher选中之后点击+号,增加goimports插件,如果说没有看到goimports插件,大家切换到命令行输出:go get -v golang.org/x/tools/cmd/goimports即可。 像老猫这样增加结束之后,而后重启IDEA即可。怎么进行验证装置胜利了呢,其实很简略,只有在前面的括号后面加上一个空格,而后保留一下就能看到成果了。 写在本章最初跟着老猫做完这些,其实大家就曾经能够运行出hello world了。前面老猫会缓缓和大家介绍相干GO语言的语法、容器等等。别落伍哦!当然有什么疑难也欢送大家关注老猫的公众号“程序员老猫”。大家一起探讨,一起提高。

November 19, 2021 · 1 min · jiezi

关于golang:GO进阶训练营jk

Gdownload:GO进阶训练营解决此种问题其实也不是很难,只是报了”Warning正告“,咱们只须要敞开”PHP谬误提醒“就好了。具体步骤以下:php 一、关上 php.inihtml 二、设置 error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICTpost 三、设置 display_errors = Offhtm

November 18, 2021 · 1 min · jiezi

关于golang:面试题Go有引用变量和引用传递么

前言在Go中如果应用过map和channel,就会发现把map和channel作为函数参数传递,不须要在函数形参里对map和channel加指针标记*就能够在函数体内扭转内部map和channel的值。 这会给人一种错觉:map和channel难道是相似C++的援用变量,函数传参的时候应用的是援用传递? 比方上面的例子: // example1.gopackage mainimport "fmt"func changeMap(data map[string]interface{}) { data["c"] = 3}func main() { counter := map[string]interface{}{"a": 1, "b": 2} fmt.Println("begin:", counter) changeMap(counter) fmt.Println("after:", counter)}程序运行的后果是: begin: map[a:1 b:2]after: map[a:1 b:2 c:3]下面的例子里,函数changeMap扭转了内部的map类型counter的值。 那map传参是应用的援用传递么?带着这个问题,咱们先回顾下什么是援用变量和援用传递。 什么是援用变量(reference variable)和援用传递(pass-by-reference)咱们先回顾下C++里的援用变量和援用传递。看上面的例子: // example2.cpp#include <iostream>using namespace std;/*函数changeValue应用援用传递*/void changeValue(int &n) { n = 2;}int main() { int a = 1; /* b是援用变量,援用的是变量a */ int &b = a; cout << "a=" << a << " address:" << &a << endl; cout << "b=" << b << " address:" << &b << endl; /* 调用changeValue会扭转内部实参a的值 */ changeValue(a); cout << "a=" << a << " address:" << &a << endl; cout << "b=" << b << " address:" << &b << endl;}程序的运行后果是: ...

November 18, 2021 · 4 min · jiezi

关于golang:一文讲透自适应熔断的原理和实现

为什么须要熔断微服务集群中,每个利用根本都会依赖肯定数量的内部服务。有可能随时都会遇到网络连接迟缓,超时,依赖服务过载,服务不可用的状况,在高并发场景下如果此时调用方不做任何解决,持续继续申请故障服务的话很容易引起整个微服务集群雪崩。比方高并发场景的用户订单服务,个别须要依赖一下服务: 商品服务账户服务库存服务 如果此时 账户服务 过载,订单服务继续申请账户服务只能被动的期待账户服务报错或者申请超时,进而导致订单申请被大量沉积,这些有效申请仍然会占用系统资源:cpu,内存,数据连贯...导致订单服务整体不可用。即便账户服务复原了订单服务也无奈自我复原。 这时如果有一个被动爱护机制应答这种场景的话订单服务至多能够保障本身的运行状态,期待账户服务复原时订单服务也同步自我复原,这种自我爱护机制在服务治理中叫熔断机制。 熔断熔断是调用方自我爱护的机制(主观上也能爱护被调用方),熔断对象是内部服务。 降级降级是被调用方(服务提供者)的避免因本身资源有余导致过载的自我爱护机制,降级对象是本身。 熔断这一词起源时咱们日常生活电路外面的熔断器,当负载过高时(电流过大)保险丝会自行熔断避免电路被烧坏,很多技术都是来自生存场景的提炼。 工作原理 熔断器个别具备三个状态: 敞开:默认状态,申请能被达到指标服务,同时统计在窗口工夫胜利和失败次数,如果达到错误率阈值将会进入断开状态。断开: 此状态下将会间接返回谬误,如果有 fallback 配置则间接调用 fallback 办法。半断开:进行断开状态会保护一个超市工夫,达到超时工夫开始进入 半断开 状态,尝试容许一部门申请失常通过并统计胜利数量,如果申请失常则认为此时指标服务已复原进入 敞开 状态,否则进入 断开 状态。半断开 状态存在的目标在于实现了自我修复,同时避免正在复原的服务再次被大量打垮。应用较多的熔断组件: hystrix circuit breaker(不再保护)hystrix-goresilience4j(举荐)sentinel(举荐)什么是自适应熔断基于下面提到的熔断器原理,我的项目中咱们要应用好熔断器通常须要筹备以下参数: 谬误比例阈值:达到该阈值进入 断开 状态。断开状态超时工夫:超时后进入 半断开 状态。半断开状态容许申请数量。窗口工夫大小。实际上可选的配置参数还有十分十分多,参考 https://resilience4j.readme.io/docs/circuitbreaker 对于教训不够丰盛的开发人员而言,这些参数设置多少适合心里其实并没有底。 那么有没有一种自适应的熔断算法能让咱们不关注参数,只有简略配置就能满足大部分场景? 其实是有的,google sre提供了一种自适应熔断算法来计算抛弃申请的概率: 算法参数: requests: 窗口工夫内的申请总数accepts:失常申请数量K:敏感度,K 越小越容易丢申请,个别举荐 1.5-2 之间算法解释: 失常状况下 requests=accepts,所以概率是 0。随着失常申请数量缩小,当达到 requests == K* accepts 持续申请时,概率 P 会逐步比 0 大开始依照概率逐步抛弃一些申请,如果故障重大则丢包会越来越多,如果窗口工夫内 accepts==0 则齐全熔断。当利用逐步恢复正常时,accepts、requests 同时都在减少,然而 K*accepts 会比 requests 减少的更快,所以概率很快就会归 0,敞开熔断。代码实现接下来思考一个熔断器如何实现。 初步思路是: 无论什么熔断器都得依附指标统计来转换状态,而统计指标个别要求是最近的一段时间内的数据(太久的数据没有参考意义也节约空间),所以通常采纳一个 滑动工夫窗口 数据结构 来存储统计数据。同时熔断器的状态也须要依附指标统计来实现可观测性,咱们实现任何零碎第一步须要思考就是可观测性,不然零碎就是一个黑盒。内部服务申请后果各式各样,所以须要提供一个自定义的判断办法,判断申请是否胜利。可能是 http.code 、rpc.code、body.code,熔断器须要实时收集此数据。当内部服务被熔断时使用者往往须要自定义疾速失败的逻辑,思考提供自定义的 fallback() 性能。上面来逐渐剖析 go-zero 的源码实现: ...

November 18, 2021 · 6 min · jiezi

关于golang:Golang日志入门与技术选型

参考文档:https://liwenzhou.com/posts/Go/zap/无论是软件开发的调试阶段还是软件上线之后的运行阶段,日志始终都是十分重要的一个环节,咱们也应该养成在程序中记录日志的好习惯。Go 语言内置的log包实现了简略的日志服务。本文介绍了规范库log的根本应用和第三日志库的选型和应用。 1、原生Loggerlog 包定义了 Logger 类型,该类型提供了一些格式化输入的办法。本包也提供了一个预约义的 “规范”logger,能够通过调用函数Print系列(Print|Printf|Println)、Fatal系列(Fatal|Fatalf|Fatalln)、和Panic系列(Panic|Panicf|Panicln)来应用,比自行创立一个 logger 对象更容易应用。 例如,咱们能够像上面的代码一样间接通过log包来调用下面提到的办法,默认它们会将日志信息打印到终端界面: package mainimport ( "log")func main() { log.Println("这是一条很一般的日志。") v := "很一般的" log.Printf("这是一条%s日志。\n", v) log.Fatalln("这是一条会触发fatal的日志。") log.Panicln("这是一条会触发panic的日志。")}编译并执行下面的代码会失去如下输入: 2017/06/19 14:04:17 这是一条很一般的日志。2017/06/19 14:04:17 这是一条很一般的日志。2017/06/19 14:04:17 这是一条会触发fatal的日志。logger 会打印每条日志信息的日期、工夫,默认输入到零碎的规范谬误。Fatal 系列函数会在写入日志信息后调用 os.Exit(1)。Panic 系列函数会在写入日志信息后 panic。 1.1 配置 logger配置默认状况下的 logger 只会提供日志的工夫信息,然而很多状况下咱们心愿失去更多信息,比方记录该日志的文件名和行号等。log规范库中为咱们提供了定制这些设置的办法。log规范库中的Flags函数会返回规范 logger 的输入配置,而SetFlags函数用来设置规范 logger 的输入配置。 func Flags() intfunc SetFlags(flag int)1.1.1 flag 选项log规范库提供了如下的 flag 选项,它们是一系列定义好的常量。 const ( // 管制输入日志信息的细节,不能管制输入的程序和格局。 // 输入的日志在每一项后会有一个冒号分隔:例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message Ldate = 1 << iota // 日期:2009/01/23 Ltime // 工夫:01:23:23 Lmicroseconds // 微秒级别的工夫:01:23:23.123123(用于加强Ltime位) Llongfile // 文件全路径名+行号: /a/b/c/d.go:23 Lshortfile // 文件名+行号:d.go:23(会笼罩掉Llongfile) LUTC // 应用UTC工夫 LstdFlags = Ldate | Ltime // 规范logger的初始值)上面咱们在记录日志之前先设置一下规范 logger 的输入选项如下: ...

November 17, 2021 · 2 min · jiezi

关于golang:Go-iota-原理和源码剖析

iota 是 Go 语言的一个保留字,用作常量计数器。因为 iota 具备自增个性,所以能够简化数字增长的常量定义。iota 是一个具备魔法的关键字,往往令初学者难以了解其原理和应用办法。本文会从书写办法、应用场景、实现原理以及优缺点等各方面分析 iota 关键字。 1. 书写办法正确写法: const ( FirstItem = iota SecondItem ThirdItem)// 或者const SingleItem = iota谬误写法: var FirstItem = iota// 或者println(iota)iota 只能用于常量表达式,而且必须在 const 代码块中呈现,不容许呈现在其它地位。 2. 应用场景iota 的次要应用场景用于枚举。Go 语言的设计准则谋求极尽简化,所以没有枚举类型,没有 enum关键字。 Go 语言通常应用常量定义代替枚举类型,于是 iota 经常用于其中,用于简化代码。例如: package mainconst ( B = 1 << (10 * iota) // 1 << (10*0) KB // 1 << (10*1) MB // 1 << (10*2) GB // 1 << (10*3) TB // 1 << (10*4) PB // 1 << (10*5) EB // 1 << (10*6) ZB // 7 << (10*5))func main() { println(B, KB, MB, GB, TB)}输入后果: ...

November 17, 2021 · 2 min · jiezi

关于golang:极客大学云原生训练营

download:极客大学-云原生训练营我需要增加一个值为嵌套字典中的每个项减少一个的键。我一直在尝试使用dict['key']='value'语法,但无奈使其用于嵌套字典。我相信这很简略。 我的字典:mydict={'a':{'result':[{'key1':'value1','key2':'value2'}, {'key1':'value3','key2':'value4'}]}} 这是将密钥增加到字典次要部分的代码:for x in range(len(mydict)): number = 1+x str(number) mydict[d'index']=number print mydict out: {d'index':d'1',d'a'{d'result':[...]}}我想将新的键和值增加到方括号内的小词典中:{'a':{'result':[{'key1':'value1',...,'index':'number'}]}} 如果我尝试在for loop的最初一行中增加更多层,则会出现回溯谬误:Traceback (most recent call last): File "C:27\program.py", line 34, in main() File "C:\Python27\program.py", line 23, in main mydict'a'['index']=number TypeError: list indices must be integers, not unicode

November 16, 2021 · 1 min · jiezi

关于golang:Go常见坑Go语言里被defer的函数一定会执行么

前言大家都晓得Go编程中,假如在函数F里,执行了defer A(),那在函数F失常return之前或者因为panic要完结运行之前,被defer关键字润饰的函数调用A()都会被执行到。 比方上面的2个例子: test1()会在main完结之前执行// defer1.gopackage mainimport ( "fmt")func test1() { fmt.Println("test")}func main() { fmt.Println("main start") defer test1() fmt.Println("main end")}这个例子输入的后果是: main startmain endtesttest1()会在panic之前执行// defer2.gopackage mainimport ( "fmt")func test1() { fmt.Println("test")}func test2() { panic(1)}func main() { fmt.Println("main start") defer test1() test2() fmt.Println("main end")}这个例子输入的后果是: main starttestpanic: 1goroutine 1 [running]:main.test2(...) /path/to/defer2.go:13main.main() /path/to/defer2.go:18 +0xb8exit status 2问题如果在函数F里,defer A()这个语句执行了,是否意味着A()这个函数调用肯定会执行? 这里大家能够先脑补一会。 请看上面的例子: // defer3.gopackage mainimport ( "fmt" "os")func test1() { fmt.Println("test")}func main() { fmt.Println("main start") defer test1() fmt.Println("main end") os.Exit(0)}下面的代码运行后果会是怎么样? ...

November 15, 2021 · 2 min · jiezi

关于golang:Go-defer-特性和使用场景

golang 的 defer 语句用于提早调用。defer 会在以后函数返回之前执行 defer 注册的函数。比方 defer func_defer() 这样语句会让你注册一个函数变量到 defer 的全局链表中,在 defer 语句所在的函数退出之前调用。 defer 能够代替其它语言中 try…catch… 语句,也能够用来解决开释资源等收尾操作,比方敞开文件句柄、敞开数据库连贯等。defer 还能用于 panic 的 recovery。 1. defer 的个性咱们先深刻的分析下 defer 具备的个性,知其然也。这些个性是须要咱们记住的特点,能力更好的了解 defer 应用的场景。 1) 提早调用package mainfunc main() { defer println("--- defer ---") println("--- end ---")}运行后果: --- end ------ defer ---defer 会在 main 函数所有语句之后, return 之前时候调用。外围要点: 提早调用:defer 语句自身尽管是 main 的第一行,然而 println("--- end ---") 先打印的;defer 关键字肯定是处于函数上下文:defer 必须放在函数外部; 2) LIFO一个函数中含有有多个 defer,调用程序采纳压栈式执行,后入先出(LIFO)。 package mainimport ( "strconv")func main() { for i := 1; i <= 3; i++ { defer println("defer -->" + strconv.Itoa(i)) } println("--- end ---")}压栈式执行,也就是说先注册的函数后调用。如上,咱们注册的程序式 1,2,3,最初打印 “--- end ---”,所以执行的后果天然是反着来的,程序输入: ...

November 15, 2021 · 1 min · jiezi

关于golang:Docker-系列docker-学习-五容器数据卷

什么是容器数据卷思考一个问题,咱们为什么要应用 Docker? 次要是为了能够将利用和环境进行打包成镜像,一键部署。 再思考一个问题,容器之间是互相隔离的,如果咱们在容器中部署相似 mysql 这样的组件,如果把该容器删除掉,那么 mysql 的数据也会被删掉了,数据失落了,咱们删库跑路真刺激 事实上,咱们可不能让这么有危险的事件存在,因而有了卷技术 卷技术是容器之间能够共享数据的技术,Docker 容器中产生数据,将数据同步到本地 例如咱们将 Docker mysql 容器中的 /usr/mysql 目录挂载到宿主机的/home/mysql 目录 应用卷技术,咱们就能够让数据得以长久化 实际上操作起来就是挂载目录,将 Docker 容器外面的目录,挂载到宿主机上的某个目录,这就能够将数据长久化和同步了, Docker 容器间的数据共享依然是这样做的 咱们如何应用数据卷?启动容器的时候,间接应用 -v命令就能够进行数据卷的挂载 docker run -it -v 宿主机目录:容器目录 镜像名咱们来尝试启动一个 nginx,并将宿主机的 /home/test 目录和 nginx 的 /home 目录挂载起来 #docker run -d -v /home/test:/home nginx此时咱们在宿主机的 /home/test 目录下建一个 test.txt 并且写入一些字符串,再查看容器的 /home 目录 是否有 test.txt # 宿主机root@iZuf66y3tuzn4wp3h02t7pZ:/home/test# echo xiaomotong >> test.txt# 容器root@c8405d03a9a1:/home# lstest.txtroot@c8405d03a9a1:/home# cat test.txtxiaomotong咱们在容器的/home 目录下创立一个test2.txt 文件,同样写入一些字符串,再查看 宿主机的 /home/test 目录是否有 test2.txt ...

November 14, 2021 · 3 min · jiezi

关于golang:如何使用Go语言写出面向对象风格的代码

原文链接:如何应用Go语言写出面向对象格调的代码 前言哈喽,大家好,我是asong。在上一篇文章:小白也能看懂的context包详解:从入门到精通 剖析context的源码时,咱们看到了一种编程办法,在构造体里内嵌匿名接口,这种写法对于大多数初学Go语言的敌人看起来是懵逼的,其实在构造体里内嵌匿名接口、匿名构造体都是在面向对象编程中继承和重写的一种实现形式,之前写过java、python对面向对象编程中的继承和重写应该很相熟,然而转Go语言后写出的代码都是面向过程式的代码,所以本文就一起来剖析一下如何在Go语言中写出面向对象的代码。面向对象程序设计是一种计算机编程架构,英文全称:Object Oriented Programming,简称OOP。OOP的一条根本准则是计算机程序由单个可能起到子程序作用的单元或对象组合而成,OOP达到了软件工程的三个次要指标:重用性、灵活性和扩展性。OOP=对象+类+继承+多态+音讯,其中外围概念就是类和对象。 这一段话在网上介绍什么是面向对象编程时经常出现,大多数学习Go语言的敌人应该也都是从C++、python、java转过来的,所以对面向对象编程的了解应该很深了,所以本文就没必要介绍概念了,重点来看一下如何应用Go语言来实现面向对象编程的编程格调。 类Go语言自身就不是一个面向对象的编程语言,所以Go语言中没有类的概念,然而他是反对类型的,因而咱们能够应用struct类型来提供相似于java中的类的服务,能够定义属性、办法、还能定义结构器。来看个例子: type Hero struct { Name string Age uint64}func NewHero() *Hero { return &Hero{ Name: "盖伦", Age: 18, }}func (h *Hero) GetName() string { return h.Name}func (h *Hero) GetAge() uint64 { return h.Age}func main() { h := NewHero() print(h.GetName()) print(h.GetAge())}这就一个简略的 "类"的应用,这个类名就是Hero,其中Name、Age就是咱们定义的属性,GetName、GetAge这两个就是咱们定义的类的办法,NewHero就是定义的结构器。因为Go语言的个性问题,结构器只可能依附咱们手动来实现。 这里办法的实现是依赖于构造体的值接收者、指针接收者的个性来实现的。 封装封装是把一个对象的属性私有化,同时提供一些能够被外界拜访的属性和办法,如果不想被外界拜访,咱们大可不必提供办法给外界拜访。在Go语言中实现封装咱们能够采纳两种形式: Go语言反对包级别的封装,小写字母结尾的名称只能在该包内程序中可见,所以咱们如果不想裸露一些办法,能够通过这种形式公有包中的内容,这个了解比较简单,就不举例子了。Go语言能够通过 type 关键字创立新的类型,所以咱们为了不裸露一些属性和办法,能够采纳创立一个新类型的形式,本人手写结构器的形式实现封装,举个例子:type IdCard stringfunc NewIdCard(card string) IdCard { return IdCard(card)}func (i IdCard) GetPlaceOfBirth() string { return string(i[:6])}func (i IdCard) GetBirthDay() string { return string(i[6:14])}申明一个新类型IdCard,实质是一个string类型,NewIdCard用来结构对象, ...

November 14, 2021 · 2 min · jiezi

关于golang:推荐高效人士的第二大脑

Notion 是一款将笔记、知识库和工作治理整合的合作工具,能够作为第二大脑,构建集体常识体系。它将“万物皆对象”的思维使用到笔记中,让使用者能够天马行空地去发明、拖拽、链接 Notion能够成为集体的数据库,而非单纯的笔记工具,实现信息存储、信息处理、信息查问的工作。信息处理简略来说就是给数据加上Tag、关键词等形式建设起信息之间的分割从而不便用户可能高效查问到对应的信息,而信息查问才是最重要的,这决定着产品是一个集体数据库还是笔记工具 基本功能Notion 最具创造性的中央就在于颠覆了用户脑子里对笔记利用的刻板印象,从头设计了一套好像来自将来的页面、编辑器、表格,别离对应着 Page、Block、Database这三个局部 Page的有限层级能让你做出属于本人的wikiBlock的多样性能让你把想要的所有连结起来Datsbase让你的检索和应用更加便捷 高级个性模块组合因为Block的多样性,能够在Page中将任意的Block组合起来,造成笔记/工作治理/打算治理/wiki等,并且反对Page、Block、DataBase 的相干转化,自由度十分高 有限层级能够自在地在Page中链接其它Page或者数据库传统的笔记利用以「笔记」和「笔记本」来辨别「文件」和「文件夹」。 以印象笔记为例,它的 笔记本组、笔记本、笔记 设计,最多只反对三个层级。层级之外还有标签来分割笔记。最大特点是笔记本只能存储笔记列表,笔记中存储文本。 Notion 则采纳了有限层级 Pages 设计,有上面几个特点: 每个Page中能够写内容如果须要嵌套关系时,能够让一个 Page 中蕴含多个 Page。Notion 没有标签体系,通过 /Link to Page 来实现 Pages 之间的跳转,或用 /Create Linked Database 来连贯到数据库 反向链接Notion 的反向链接(backlink)是主动创立的,Notion 为呼出反向链接(backlink)提供了三种形式,别离是[[、@ 、+,不过这里我举荐应用@。 创立结束后,点击链接,链接的页面题目下方就会呈现一个↙backlinks的操作按钮,点击关上即可看到链接的页面。Notion 的反向链接(backlink)显示以后页面被援用的所有地位。比照之前复制链接的操作,大大晋升了操作效率。 反向链接(backlink)能用来做什么? 在 wiki 页面上查看相关联的主题能够查看链接到同一我的项目的所有扩散的笔记、文档和工作做笔记时链接感兴趣的主题,主动创立想法合集模板按钮模板按钮(Template Button),能够用于疾速创立模板化的内容,非常不便。你只须要制作一个模板,后续通过模板按钮创立新的表格,而不必从头创立新的表格。 模板按钮能用来做什么? 创立日报/周打算/月打算/年打算等模板创立读书笔记模板数据库数据库能够了解为集体的图书馆,依据不同的用处能够建设不同的数据库,并且通过 Properties 进行 SELECT,通过 Filter 进行 WHERE,通过 Sort 进行 ORDER BY; Notion 数据库(Database)有以下三大亮点: 高度定制化:你能够增加任何数据类型的属性,其中比拟有意思的是Relation类型,能够关联到其它数据库独立页面:每个数据条目都是一个独立的Notion页面,可增加更多信息多维视图(View):你能够通过增加多种视图(View)来浏览数据库(Database)数据库能用来做什么? 创立各种各样的数据列表(书单、文章库、选题库、关注列表)表格个别说创立数据库,通常指创立数据库的表格模式 看板Notion 的看板性能和 Trello 较为类似,它也能像 Trello 一样实现拖拽治理卡片、增加组员和日期的性能。但和 Trello 相比,Notion 短少了订阅、归档等团队合作罕用的性能。 ...

November 13, 2021 · 1 min · jiezi

关于golang:Docker-系列docker-学习-四镜像相关原理

【Docker 系列】docker 学习 四,镜像相干原理镜像是什么?镜像是一种轻量级的,可执行的独立的软件包。 镜像用来打包软件的运行环境和基于运行环境开发的软件,它蕴含运行某些软件所须要的所有内容,例如:代码,运行时库,环境变量和配置文件等等 所有的利用,能够间接打包 docker 镜像,一键部署,一键运行 失去镜像形式有哪些?间接拷贝其余 docker 镜像本人制作一个镜像 DockerFile从近程仓库下载,如 dockerhubDocker 镜像的加载原理UnionFSUnionFS,是联结文件系统,还记的咱们 docker 学习二 外面装置 redis 的时候,呈现的分层下载吗 这就是联结文件系统 UnionFS 联结文件系统,是一种分层,轻量级并且高性能的文件系统 它反对对文件系统的批改作为一次提交来一层一层的叠加,同时能够将不同目录挂载到一个虚构文件系统下 UnionFS 联结文件系统是 Docker 镜像的根底,镜像还能够通过分层来继承,基于根底的镜像,咱们能够制作成各种利用镜像 个性: 联结文件系统一次同时加载多个文件系统,联结加载会把各层的文件系统叠加起来,最终的文件系统会蕴含所有底层的文件和目录 Docker 的镜像加载原理是什么呢?图片来源于网络 Docker 的镜像是有一层一层的文件系统组成的,这个层级的文件系统就叫做联结文件系统,个别底下的层都是共用的 个别系统启动,是一个加载的过程,这个过程是 bootloader 疏导加载 kernel,linux 操作系统刚启动的时候还会加载 bootfs 文件系统,而咱们的 Docker 镜像最底层就是 bootfs bootfsboot file system 是一个文件系统,次要是蕴含 bootloader 和 kernel 当 boot 加载结束之后,整个内核都在运行正在内存中的,此时内存的使用权曾经由 bootfs 交接给内核,这个时候零碎会将 bootfs 卸载掉 rootfs在来说一下 rootfs,root file system,根文件系统,它是在 bootfs 之上的,就是蕴含了,linux 操作系统中的 /dev ,/proc,/bin,/etc 等目录和文件 ...

November 12, 2021 · 2 min · jiezi

关于golang:Go-defer-原理和源码剖析

Go 语言中有一个十分有用的保留字 defer,defer 语句能够调用一个函数,该函数的执行被推延到包裹它的函数返回时执行。 defer 语句调用的函数,要么是因为包裹它的函数执行了 return 语句,达到了函数体的末端,要么是因为对应的 goroutine 产生了 panic。 在理论的 go 语言程序中,defer 语句能够代替其它语言中 try…catch… 的作用,也能够用来解决开释资源等收尾操作,比方敞开文件句柄、敞开数据库连贯等。 1. 编译器编译 defer 过程defer dosomething(x)简略来说,执行 defer 语句,实际上是注册了一个稍后执行的函数,确定了函数名和参数,但不会立刻调用,而是把调用过程推延到以后函数 return 或者产生 panic 的时候。 咱们先理解一下 defer 相干的数据结构。 1) struct _defer 数据结构go 语言程序中每一次调用 defer 都生成一个 _defer 构造体。 type _defer struct { siz int32 // 参数和返回值的内存大小 started boul heap boul // 辨别该构造是在栈上调配的,还是对上调配的 sp uintptr // sp 计数器值,栈指针; pc uintptr // pc 计数器值,程序计数器; fn *funcval // defer 传入的函数地址,也就是延后执行的函数; _panic *_panic // panic that is running defer link *_defer // 链表}咱们默认应用了 go 1.13 版本的源代码,其它版本相似。 ...

November 12, 2021 · 6 min · jiezi

关于golang:gdb-golang-查看iface-内部结构

环境阐明macOs bigSur 11.4GNU gdb (GDB) 10.2 代码筹备package maintype Ner interface { a() b(int) c(string) string}type N intfunc (N) a() {}func (*N) b(i int) { return}func (*N) c(s string) string { return "c"}func main() { var n N var t Ner = &n t.a()}命令执行go build -gcflags "-N -l" -ldflags=-compressdwarf=false main.gogdb main失常输入图 设置断点(在第25行),而后执行(gdb) b main.go:25Loading Go Runtime support.(gdb) b main.go:25Breakpoint 1 at 0x1054d98: file /Users/didi/GolandProjects/goLarnNote/Chapter7/Iface/debugGDB/main.go, line 25.(gdb) runStarting program: /Users/didi/GolandProjects/goLarnNote/Chapter7/Iface/debugGDB/main [New Thread 0x2603 of process 72590][New Thread 0x1a03 of process 72590]warning: unhandled dyld version (17)[New Thread 0x2403 of process 72590][New Thread 0x2507 of process 72590][New Thread 0x2203 of process 72590]Thread 2 hit Breakpoint 1, main.main () at /Users/didi/GolandProjects/goLarnNote/Chapter7/Iface/debugGDB/main.go:2525 t.a()查看信息并打印(gdb) info localst = {tab = 0x1076b60 <N,main.Ner>, data = 0xc00003c748}n = 0(gdb) p *t.tab $1 = {inter = 0x105b800 <type.*+26912>, _type = 0x105b580 <type.*+26272>, hash = 3289684567, _ = "\000\000\000", fun = {16812096}}(gdb) p *t.tab_type There is no member named tab_type.(gdb) p *t.tab.inter$2 = {typ = {size = 16, ptrdata = 16, hash = 1801897693, tflag = 7 '\a', align = 8 '\b', fieldAlign = 8 '\b', kind = 20 '\024', equal = {void (void *, void *, bool *)} 0x105b818 <type.*+26936>, gcdata = 0x1065b18 <func.*+254> "\002", str = 2790, ptrToThis = 9664}, pkgpath = { bytes = 0x105500a <type.*+298> ""}, mhdr = []runtime.imethod = {{name = 8, ityp = 15552}, {name = 11, ityp = 16128}, {name = 14, ityp = 20288}}}后续todo联合iface,eface的构造来分析接口判等 等系列问题 ...

November 11, 2021 · 2 min · jiezi

关于golang:Go-开源-12-周年Russ-Cox-发文庆贺

自 2009 年 11 月正式对外公布后,至今 Go 开源已走过整整 12 个年头。刚刚,Go 开发团队技术 leader Russ Cox 就专门撰文庆贺 “Go 开源 12 周年”。 在这篇博客文章中,Russ Cox 对 Go 开源今年以来的变动及所获得停顿做了回顾,并对下一阶段的倒退进行了瞻望。 Russ Cox 提到了将 godoc.org 替换成 pkg.go.dev,以及新域名 go.dev 的启用,可将所有官网 Go 站点整合至对立域名下。 往年 2 月,Go 1.16 版本增加了对 macOS ARM64 的反对,以及文件系统接口和嵌入文件、默认启用 modules 等多项改良优化。 往年 8 月,Go 1.17 版本增加了对 Windows ARM64 的反对,大大晋升了 TLS 明码套件决策的易用性和安全性;修剪模块图 (pruned module graphs)及全新易读的构建束缚语法的引入,让 Go Modules 在大型项目中更高效。Go 1.17 版本还在底层上将 x86-64 的 Go 函数切换至基于寄存器的调用约定, 让 CPU 密集型应用程序的性能进步了 5-15%。 ...

November 11, 2021 · 1 min · jiezi

关于golang:mac-golanggoprotovalidatorsvalidatorproto-文件在GoLand中不识别

在写proto文件生成pb文件脚本的时候,提醒github.com/mwitkow/go-proto-validators/validator.proto: File not found。为了可能更分明理解场景,先介绍一下我的项目文件目录,如下图所示。 上面抉择protobuf-spec文件下,任意一个proto文件为例来做展现和阐明问题。节选proto文件局部代码,代码如下: syntax = "proto3"; package ofc.app; import "google/protobuf/empty.proto"; import "github.com/mwitkow/go-proto-validators/validator.proto"; //增加利用 message AppRequest{ int64 cid = 1; string appkey = 2; // @inject_tag: v:"required#利用名不能为空" string name = 3[(validator.field) = {string_not_empty: true}]; // @inject_tag: v:"required#行业类型不能为空" string industry_type = 4[(validator.field) = {string_not_empty: true}]; string info = 5; }依据本机环境,编写script.sh脚本文件,依据proto生成pb文件: # !bin/shproto_files=`find ./api/protobuf-spec -name "*.proto"`for proto_file in ${proto_files[*]}do `protoc -I. \ -I$GOPATH/pkg/mod/github.com/mwitkow/go-proto-validators@v0.3.2 \ -I$GOPATH/pkg/mod/github.com/grpc-ecosystem/grpc-gateway@v1.14.6/third_party/googleapis \ --govalidators_out=./api/protobuf \ --go_out=plugins=grpc:./api/protobuf \ ${proto_file}`doneecho "success"在执行script.sh的时候,提醒github.com/mwitkow/go-proto-validators/validator.proto: File not found,如下图所示。 ...

November 11, 2021 · 1 min · jiezi

关于golang:GO开发环境开发工具安装配置

windows装置下载安装Go官网下载地址:https://golang.org/dl/ 因为网络问题大家可能关上有些慢,或者下载失败。大家也能够从下边下载。下载执行后大家间接一路下一步就行了。 配置环境变量(win+pause关上设置)--> 高级设置 --> 高级 --> 环境变量 配置GOPATH;他是用来寄存你我的项目工程代码的中央。而后将GOPATH 和 go装置的路劲配置到path中。 而后通过cmd执行go version查看版本,当看到版本后证实装置胜利。 创立工程目录在咱们GOPATH中创立 bin pkg src 开发工具go语言的开发工具有很多,这个依据集体的爱好进行抉择。vscode、goland 、IntelliJ + Go 插件、LiteIDE等都行。他就是一个工具不必太纠结。 vscode+go插件mac和window装置一样的。去官网下载https://code.visualstudio.com/download在vscode中搜寻go,而后装置。为了方便使用你能够先装置一个中文插件。 装置胜利后在装置go语言开发工具安装包(代码提醒,代码主动补全等性能)。shift+ctrl+p 而后输出go:install抉择Go:Install/Update Tools 全选,而后装置。 装置问题解决如果装置过程中显示如下无奈装置。 Tools environment: GOPATH=C:\workspace\goprojectInstalling 10 tools at C:\workspace\goproject\bin in module mode. gopkgs go-outline gotests gomodifytags impl goplay dlv dlv-dap staticcheck goplsInstalling github.com/uudashr/gopkgs/v2/cmd/gopkgs@latest FAILED{ "killed": false, "code": 1, "signal": null, "cmd": "C:\\Program Files\\Go\\bin\\go.exe install -v github.com/uudashr/gopkgs/v2/cmd/gopkgs@latest", "stdout": "", "stderr": "go install: github.com/uudashr/gopkgs/v2/cmd/gopkgs@latest: module github.com/uudashr/gopkgs/v2/cmd/gopkgs: Get \"https://proxy.golang.org/github.com/uudashr/gopkgs/v2/cmd/gopkgs/@v/list\": dial tcp 172.217.27.145:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.\n"}Installing github.com/ramya-rao-a/go-outline@latest FAILED{ "killed": false, "code": 1, "signal": null, "cmd": "C:\\Program Files\\Go\\bin\\go.exe install -v github.com/ramya-rao-a/go-outline@latest", "stdout": "", "stderr": "go install: github.com/ramya-rao-a/go-outline@latest: module github.com/ramya-rao-a/go-outline: Get \"https://proxy.golang.org/github.com/ramya-rao-a/go-outline/@v/list\": dial tcp 172.217.27.145:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.\n"}Installing github.com/cweill/gotests/gotests@latest FAILED{ "killed": false, "code": 1, "signal": null, "cmd": "C:\\Program Files\\Go\\bin\\go.exe install -v github.com/cweill/gotests/gotests@latest", "stdout": "", "stderr": "go install: github.com/cweill/gotests/gotests@latest: module github.com/cweill/gotests/gotests: Get \"https://proxy.golang.org/github.com/cweill/gotests/gotests/@v/list\": dial tcp 172.217.27.145:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.\n"}Installing github.com/fatih/gomodifytags@latest FAILED{ "killed": false, "code": 1, "signal": null, "cmd": "C:\\Program Files\\Go\\bin\\go.exe install -v github.com/fatih/gomodifytags@latest", "stdout": "", "stderr": "go install: github.com/fatih/gomodifytags@latest: module github.com/fatih/gomodifytags: Get \"https://proxy.golang.org/github.com/fatih/gomodifytags/@v/list\": dial tcp 172.217.27.145:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.\n"}Installing github.com/josharian/impl@latest FAILED{ "killed": false, "code": 1, "signal": null, "cmd": "C:\\Program Files\\Go\\bin\\go.exe install -v github.com/josharian/impl@latest", "stdout": "", "stderr": "go install: github.com/josharian/impl@latest: module github.com/josharian/impl: Get \"https://proxy.golang.org/github.com/josharian/impl/@v/list\": dial tcp 142.251.42.241:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.\n"}起因是网络问题。懂得都懂。咱们只需配置一下国内的代理从新下载安装一下插件就好了。 ...

November 9, 2021 · 2 min · jiezi

关于golang:开源项目|Go-开发的一款分布式唯一-ID-生成系统

原文连贯: 开源我的项目|Go 开发的一款分布式惟一 ID 生成零碎 明天跟大家介绍一个开源我的项目:id-maker,次要性能是用来在分布式环境下生成惟一 ID。上周停更了一周,也是用来开发和测试这个我的项目的相干代码。 美团有一个开源我的项目叫 Leaf,应用 Java 开发。本我的项目就是在此思路的根底上,应用 Go 开发实现的。 我的项目整体代码量并不多,不论是想要在理论生产环境中应用,还是想找个我的项目练手,我感觉都是一个不错的抉择。 我的项目背景在大部分零碎中,全局惟一 ID 都是一个强需要。比方快递,外卖,电影等,都须要生成惟一 ID 来保障单号惟一。 那业务系统对 ID 号的要求有哪些呢? 全局唯一性:不能呈现反复的 ID 号,既然是惟一标识,这是最根本的要求。趋势递增:在 MySQL InnoDB 引擎中应用的是汇集索引,因为少数 RDBMS 应用 B-tree 的数据结构来存储索引数据,在主键的抉择下面咱们应该尽量应用有序的主键保障写入性能。枯燥递增:保障下一个 ID 肯定大于上一个 ID,例如事务版本号、IM 增量音讯、排序等非凡需要。信息安全:如果 ID 是间断的,歹意用户的扒取工作就非常容易做了,间接依照程序下载指定 URL 即可;如果是订单号就更危险了,竞对能够间接晓得咱们一天的单量。所以在一些利用场景下,会须要 ID 无规则、不规则。在此背景下,有一个高可用的惟一 ID 生成零碎就很重要了。 我的项目应用生成 ID 分两种形式: 依据数据库生成 ID。依据雪花算法生成 ID。应用上提供两种形式来调用接口: HTTP 形式gRPC 形式HTTP 形式1、健康检查: curl http://127.0.0.1:8080/ping2、获取 ID: 获取 tag 是 test 的 ID: curl http://127.0.0.1:8080/v1/id/test3、获取雪花 ID: curl http://127.0.0.1:8080/v1/snowidgRPC 形式1、获取 ID: ...

November 9, 2021 · 1 min · jiezi