关于go:Go设计模式之选项模式

在日常的Go程序开发中,函数(办法)参数的传递是必不可少的一部分,如果参数比拟少,能够在办法参数局部间接列出,如果参数很多,可不可以一个一个列举呢,答案是能够的。然而这种形式存在两个问题: 参数很多,列举进去之后办法的参数局部会很长,不美观;每一个参数都有对应的数据类型,太多的参数在函数(办法)调用的时候容易写错程序; func Test(a []int, b, c,d string, e, f, g, h int) { // 存在多个参数类型}既然存在上边两个问题,咱们来优化一下,这些参数能够放在一个构造体里,通过构造体传递参数,如下: type param struct { a []int b string c string d string e int}func Test(p param) {}通过上边的优化就能够解决第一种形式存在的问题,优化后的形式也是在传参中的比拟罕用的。咱们持续思考一下,如果在开发中咱们有可选参数的需要呢,这种需要在初始化构造体的时候会比拟常见,有局部参数是必须在初始化的时候传递的,而另外一部分参数则是不同的调用方传递不同的可选参数。针对这种场景办法二也能够解决,在初始化的时候把程序用到的所有参数都初始化,然而这种解决并不满足可选参数的需要。Go原生并没有像Python等语言一样反对可选参数,须要开发者本人来实现,这个时候就须要用到选项模式了。如下: type Base struct { Id string Name string Age int School string Record string}type Options func(*Base)func WithAge(age int) Options { return func(base *Base) { base.Age = age }}func WithSchool(school string) Options { return func(base *Base) { base.School = school }}func WithRecord(record string) Options { return func(base *Base) { base.Record = record }}func New(id, name string, opt ...Options) *Base { base := &Base{ Id: id, Name: name, } for _, op := range opt { op(base) } return base}在上边的程序中,Id和Name两个字段是在初始化的时候须要要传递的,其余的字段则是可选的,那么其余的字段就能够创立本人的With办法,在初始化的时候通过下边的形式来调用,须要用到哪个可选参数,就调用对应的With办法即可,如下: ...

May 18, 2023 · 2 min · jiezi

关于go:Go121-速览Go-终于打算进一步支持-WebAssembly-了

大家好,我是煎鱼。 之前写过一篇对于 Go WebAssembly 的相干文章 《一分钟搞明确!疾速把握 Go WebAssembly》,明天带来一则新音讯。 想着 Go 过来了那么多年了,只在 Go1.11 反对了 WebAssembly1.0 的局部性能(js/syscall),还没有残缺的反对 WebAssembly System Interface(WASI)。这可真的是大写的难堪。 根本也没怎么更新新个性。这也侧面阐明了 WebAssembly 在多语言适配的道路上,还是比拟艰苦的。 Go1.21 反对 WASI没想到,刚写完没多久。这脸啪啪的就被抽了。因为...在 Go1.21 起,Go 将会反对 WASI 的个性。预计先反对 WASI Preview1 规范,后续 WASI Preview2 成熟后会持续反对新规范。 此处变更会减少新的端口和形式,如下: Go 编译和运行:能够应用 GOOS=wasip1 GOARCH=wasm,能够反对 wasi_snapshot_preview1 规范的 API。将来大概率还会呈现 wasip2、wasip3 等相互不兼容的状况,因为 WASI 自身并还未齐全成熟。新增 syscall 包中能够应用的指令:go:wasmimport,提供 syscall 与 WASI 交互的形式。最小 Demo 体验Go 最新版本体验的话,能够装置 gotip(倡议迷信上网)。命令如下: $ go install golang.org/dl/gotip@latest$ gotip download一个简略的 Go Wasm Demo: package main func main() { println("脑子进煎鱼了")}将上述 Go 程序编译为 .wasm 文件。如下编译命令: ...

May 18, 2023 · 1 min · jiezi

关于go:domutils-工具库的使用方法介绍

domutils 是一个 Node.js 的 DOM 操作工具库,它提供了一系列办法,能够不便地对 DOM 树进行操作和遍历。该工具库是基于浏览器的 DOM API 开发的,因而具备很好的兼容性和稳定性。上面咱们来介绍一下 domutils 工具库的次要作用和应用办法。 作用domutils 工具库的次要作用是提供一些罕用的 DOM 操作方法,例如: 创立 DOM 元素:能够应用 domutils.createElement() 办法创立新的 DOM 元素,能够指定元素的标签名、属性和子节点等。查找 DOM 元素:能够应用 domutils.findOne() 和 domutils.findAll() 办法查找 DOM 树中符合条件的元素,能够指定选择器、标签名、属性等多种条件。操作 DOM 元素:能够应用 domutils.append()、domutils.insertBefore()、domutils.removeChild() 等办法对 DOM 元素进行增加、插入和删除等操作。遍历 DOM 树:能够应用 domutils.walk() 办法对 DOM 树进行遍历,能够指定遍历的方向、过滤器和回调函数等。获取和设置 DOM 属性:能够应用 domutils.getAttribute()、domutils.setAttribute() 等办法获取和设置 DOM 元素的属性。应用办法上面,咱们来介绍如何在 Node.js 环境下应用 domutils 工具库。首先,须要通过 npm 装置该包: npm install domutils装置实现后,就能够在代码中引入并应用该工具库了。上面是一个简略的示例: const domutils = require('domutils');// 创立一个 DOM 元素const el = domutils.createElement('div', { class: 'container' }, [ domutils.createElement('p', null, 'hello, world')]);// 查找符合条件的 DOM 元素const matches = domutils.findAll(el, { tag_name: 'p' });// 遍历 DOM 树,输入元素的文本内容domutils.walk(matches, node => { if (node.type === 'text') { console.log(node.data); }});// => 'hello, world'下面的示例代码中,咱们首先引入了 domutils 包。而后,应用 domutils.createElement() 办法创立一个新的 DOM 元素,蕴含一个 <div> 元素和一个子元素 <p>。接下来,应用 domutils.findAll() 办法查找该 DOM 元素中所有的 <p> 元素。最初,应用 domutils.walk() 办法遍历 <p> 元素,并输入文本内容。 ...

May 18, 2023 · 1 min · jiezi

关于go:Go框架gin框架是如何做崩溃处理的

大家好,我是渔夫子。 本文咱们介绍下recover在gin框架中的利用。首先,在golang中,如果在子协程中遇到了panic,那么主协程也会被终止。如下: package mainimport ( "github.com/gin-gonic/gin")func main() { r := gin.Default() // 在子协程中引起panic,主协程也会退出 go func() { panic("hello world") }() // Listen and Server in 0.0.0.0:8080 r.Run(":8080")}panic被形容为不可解决的谬误。在web服务中就是服务会解体。当然,这在生产环境下是不可承受的。那么,如何可能做到产生panic时技能捕捉该panic又能让服务持续衰弱运行呢? 这就是golang中提供的recover函数了。recover函数可能捕捉Panic谬误并恢复程序的失常运行。接下来,咱们看下recover函数在gin框架中是如何利用的。 首先,要提到的就是gin框架中的recovery中间件。在gin中,是通过应用该中间件来捕捉panic,并保障服务不down机的。 如果应用gin.Default()函数进行构建gin对象,那么默认就注册了Recovery中间件。 func Default() *Engine { debugPrintWARNINGDefault() engine := New() // 注册了Recovery中间件 engine.Use(Logger(), Recovery()) return engine}其次,咱们来看下Recovery()中间件都做了些什么。 Recovery()函数定义如下: func Recovery() HandlerFunc { return RecoveryWithWriter(DefaultErrorWriter)}这里的DefaultErrorWriter是默认的输入端,即os.Stderr。即指谬误的输入到什么中央。 接下来看RecoveryWithWriter函数中的实现 // RecoveryWithWriter returns a middleware for a given writer that recovers from any panics and writes a 500 if there was one.func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) HandlerFunc { if len(recovery) > 0 { return CustomRecoveryWithWriter(out, recovery[0]) } return CustomRecoveryWithWriter(out, defaultHandleRecovery)}这里有一个参数是defaultHandleRecovery,咱们看下它的实现: ...

May 17, 2023 · 1 min · jiezi

关于go:npm-工具库-yenv-简介

"yenv" 是一个 JavaScript 库,它是在 Node.js 环境中应用的 npm 包之一。它的目标是从环境变量中加载配置,以便在 Node.js 应用程序中应用。 应用 yenv,您能够在不同的环境中配置不同的变量,并依据须要轻松地加载这些变量。这些环境能够是开发、测试、生产等等。它也反对默认值和类型转换,以确保正确的配置参数被应用。 这个库还提供了一些其余性能,例如从文件中加载配置和验证配置,以确保应用程序的配置合乎预期的格局和类型。 总的来说,yenv 能够让您更轻松地治理您的 Node.js 应用程序的配置,从而进步了开发效率和应用程序的可靠性。 yenv 是一个 Node.js 的 npm 工具库,用于解决环境变量。它容许您更不便地治理不同环境(如开发、测试、生产等)的配置。yenv 的工作原理是,依据您在我的项目中定义的 .yml 文件,加载与以后环境绝对应的配置信息。 yenv 的次要劣势在于: 更简洁地定义和治理环境变量。反对类型检查和默认值,这有助于缩小因为谬误配置导致的问题。反对变量嵌套,不便地定义和拜访多级配置。具备灵便的配置笼罩和继承机制,容许在不同环境中轻松共享和笼罩配置。要装置并应用 yenv,您须要在我的项目中执行以下操作: 装置 yenv 作为我的项目的依赖项:npm install yenv在我的项目的根目录下创立一个名为 env.yml 的文件,其中蕴含您的环境变量。在代码中应用 yenv 加载环境变量:const yenv = require('yenv');const env = yenv();console.log(env.MY_VARIABLE);更多对于 yenv 的信息和示例能够在官网文档中找到:https://www.npmjs.com/package/yenv

May 16, 2023 · 1 min · jiezi

关于go:简单理解正向代理和反向代理

上一篇文章说到反向代理是用来做负载平衡的,同时我就想到了那么正向代理是不是也能够说一说,可能还是有很多人是弄不清他俩的区别是什么的吧? 那么本次文章就用借钱的例子来论述一下什么是正向代理,什么是反向代理 正向代理正向代理就是一个位于客户端和指标服务器之间的服务器,这是一个代理服务器 客户端为了从指标服务器获取内容,然而客户端因为限度无奈间接拜访到指标服务器,那么客户端就能够向一个代理服务器发送一个申请并指定指标服务器 代理服务器收到申请后,就会向指标服务器转交申请并将取得的内容返回给客户端 咱们用借钱来比喻一下,就会很容易明确 小明,想找一个老板借钱,然而小明因为本身太菜,没有方法和老板谈借钱的事件 然而小明很聪慧,他意识老板身边的秘书,而后他就通过和这个秘书沟通,将借钱的事件想秘书说分明,秘书进而去向老板借钱 整条链路,小明达到了借钱的目标,老板的钱也被借出去了,可是,老板不晓得到底是谁在借钱,只晓得钱给了秘书 这就是正向代理,个别是用在客户端侧,是属于客户端的代理,可能帮忙客户端拜访本身无法访问的服务器资源 正向代理的应用场景 能够冲破客户端本身的拜访限度能够进步拜访服务器的速度能够暗藏客户端的实在 IP第一点和第三点,通过下面借钱的例子,大家比拟好了解,正向代理服务器是帮忙客户端去拜访服务器,服务器并不知道具体的客户端是谁 进步拜访服务器的速度如何了解? 个别状况下,正向代理服务器下面都会设置一个硬件缓冲区,并且会将客户端的局部申请放到缓冲区中 当有其余客户端进来拜访的时候,正向带来服务器就能够将缓冲区中的数据给到客户端,进而进步访问速度 反向代理反向代理也是一个位于客户端和指标服务器之间的服务器 反向代理就是指以代理服务器来接管互联网上的连贯申请,而后将这些申请转发给外部的多个服务器 并将从服务器上失去的后果返回给互联网上申请的对应客户端,这个时候的代理服务器就是一个反向代理服务器 还是一个借钱的例子 老板想把钱借出去,然而老板本人懒得去找借钱的人,于是他就将钱给到某机构,让这个机构把本人的钱借出去 这个时候,小明依然缺钱,于是找到了某机构借钱,小明借到的这个钱,其实是老板的,然而小明不会晓得这个钱具体是谁的,他只晓得是机构借给他的 这就是反向代理,个别是用在服务端侧,是属于服务端的代理,个别是用来做服务端的负载平衡 反向代理的利用场景也就显而易见了吧,与下面正向代理绝对的也有如下几点: 能够做负载平衡能够进步拜访服务器的速度能够暗藏服务端的实在 IP能够做服务器的平安保障前三点都比拟好了解,第一点上一篇文章说过,那么第四点如何了解呢? 内部的申请都是先过代理服务器,再到外部服务器上的,那么在代理服务器下面就能够做一些平安的能力,例如 防 DDOS , IP 白名单,加密的能力等等 正向代理和反向代理的区别看了上述的例子对于正向代理和反向代理的区别,咱们再来简略的比照一下 正向代理,属于客户端代理,服务端不晓得到底是谁拜访本人 反向代理,用于服务端,属于服务端代理,客户端不晓得本人具体是拜访的哪个服务器 当看到正向代理和反向代理的时候,咱们想想借钱的案例就懂了 明天就到这里,学习所得,若有偏差,还请斧正 欢送点赞,关注,珍藏敌人们,你的反对和激励,是我保持分享,提高质量的能源 好了,本次就到这里 技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。 我是阿兵云原生,欢送点赞关注珍藏,下次见~

May 15, 2023 · 1 min · jiezi

关于go:Go-httpServer-graceful-shutdown遇到的奇怪问题

代码如下: package mainimport ( "context" "log" "net/http" "os" "os/signal" "sync" "time" "github.com/gin-gonic/gin")var wg sync.WaitGroupvar apiQuit = make(chan bool)func apiQuitSignal() { log.Println("quit signal") apiQuit <- true}func main() { router := gin.New() router.GET("/quit", func(c *gin.Context) { log.Println("GET /quit") apiQuitSignal() //time.AfterFunc(5*time.Second, apiQuitSignal) c.String(200, "quit") //c.String(200, "quit in 5 seconds") }) router.GET("/hello", func(c *gin.Context) { log.Println("GET /hello") c.String(200, "hello") }) srv := &http.Server{ Addr: ":8888", Handler: router, } register := func(f func()) { wg.Add(1) srv.RegisterOnShutdown(func() { defer wg.Done() f() }) } register(func() { time.Sleep(10 * time.Second) }) go func() { // 服务连贯 if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }() quit := make(chan os.Signal) signal.Notify(quit, os.Interrupt) select { case <-quit: log.Println("quit from os.Signal") case <-apiQuit: log.Println("quit from api") } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) //ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } wg.Wait() log.Println("Server Exit")}下面的服务应用apiQuit从申请quit时取得shutdown的信号,而后进行graceful shutdown操作。 ...

May 15, 2023 · 2 min · jiezi

关于go:Go框架使用gin实现http的分块传输及原理分析

大家好,我是渔夫子。 明天,跟大家聊聊gin框架中是如何实现分片输入的。次要分以下4点: 分片输入的效果图gin实现分片传输代码http分片传输的根底:transfer-encodinggin实现分片传输原理效果图首先看下分片输入的效果图: gin分片传输实现代码下面的效果图中,网页中的内容一直的输入。在gin中是次要是利用了Flush函数实现的。如下代码: package mainimport ( "fmt" "net/http" "time" "github.com/gin-gonic/gin")func main() { r := gin.Default() r.GET("/test_stream", func(c *gin.Context) { w := c.Writer header := w.Header() header.Set("Content-Type", "text/html") w.WriteHeader(http.StatusOK) w.Write([]byte(` <html> <body> `)) w.(http.Flusher).Flush() // 这里对每次循环输入都进行Flush刷新输入 for i := 0; i < 10; i++ { w.Write([]byte(fmt.Sprintf(` <h3>%d</h3> `, i))) //w.Flush() w.(http.Flusher).Flush() time.Sleep(time.Duration(1)*time.Second) } w.Write([]byte(` </body> </html> `)) w.(http.Flusher).Flush() }) r.Run("127.0.0.1:8080")}这里次要就是利用了第22行中的w.(http.Flusher).Flush()。 这里的Flush实质上就是将Write的内容立刻输入到客户端的意思。 那么,为什么通过Flush就能实现上述成果呢? 分块传输的根底:http的 transfer-encoding:chunked 协定分块传输的根底就是http中的transfer-encoding:chunked协定。在http响应报文中用头字段“Transfer-Encoding: chunked”,示意响应中的body不是一次性发送结束,而是分成了许多的块(chunk)一一发送,直到发送结束。 分块传输的编码规定如下:1)每个分块蕴含两个局部,<长度头>和&<数据块>2) <长度头>是以 CRLF(回车换行,即\r\n)结尾的一行明文,用 16 进制数字示意长度3) <数据块>紧跟在<长度头>后,最初也用 CRLF 结尾,但数据不蕴含 CRLF4)最初用一个长度为 0 的块示意数据传输完结,即“0\r\n\r\n”。 ...

May 15, 2023 · 1 min · jiezi

关于go:一名Java开发学习的Go语言学习笔记一

版本日期备注 1.02023.5.15文章首发本文首发于泊浮目标掘金:https://juejin.cn/user/1468603264665335 0. 概要最近因为业务须要在学Go语言,尽管之前也用过别的语言,但主力语言始终是Java。在这里也想次要想用Java做比照,写几篇笔记。 这篇次要是讲语言自身及较为外表的一些比照。 这里的比照用的是Java8,Go的版本是1.20.2。 1. Compile与Runtime在动态、动静链接反对方面,两者雷同。Go在Runtime时,程序结构是关闭的。但Java并不是,基于Classloader的动静加载,实现许多灵便的个性,比方Spring,FlinkSQL。但这样做会让Java利用的Startup工夫更长。Java的Runtime久经打磨,也是面向长时间利用设计。Go间接编译成可执行文件,而Java是先编译成Class文件,而后JVM去解释执行。有趣味的同学能够看我之前的的一篇笔记:《笔记:追寻云原生的Java》 2. 命名标准Go语言在变量命名标准遵循的是C语言格调,越简略越好。Java倡议遵循见名知意。比方: 下标:Java倡议index,Go倡议i值:Java倡议value,Go倡议v我认为语言上偏简略的设计,则对工程师的能力要求更强。3. 变量的零值反对这点其实是Go在设计时,认为C在这下面有所有余——未被显式初始化的对象,其值是不确定的(当然有些编译器反对做初始化)。Go对于变量默认值的形容是:当通过申明或调用new为变量调配存储空间,或者通过复合文字字面量或调用make创立新值,且不提供显式初始化时,Go会为变量或值提供默认值。 所有整型类型:0浮点类型:0.0布尔类型:false字符串类型:""指针、interface、切片(slice)、channel、map、function:nil另外,Go的零值初始是递归的,即数组、构造体等类型的零值初始化就是对其组成元素逐个进行零值初始化。比照Java,我认为这是个仁者见仁智者见智的事。default值并不一定是你想要的值,如果你遗记初始化了,在runtime时间接炸进去也是个好的抉择,而不是把问题藏起来。当然,对Go默认值相熟的人,这对他们来说能够少写一点代码,很难受。4. 规范库对于工程能力的反对无论是Format还是Test以及模块治理,Go都是开箱即用的,比拟难受。如果规范库确实很好用、社区的迭代能力强,那这是个坏事,当初看来就是。Java对于这块都是通过了长期的倒退,相干的工具链比拟成熟,相当于是物竞天择留下来的。5. Composite litera(复合字面值)可能没人听过这个说法,举几个例子: m := map[int]string {1:"hello", 2:"gopher", 3:"!"}复合字面值由两局部组成:一部分是类型,比方上述示例代码中赋值操作符右侧的map[int]string;另一部分是由大括号{}包裹的字面值。 在申明对象时,也有相似的用法: // $GOROOT/src/net/http/transport.govar DefaultTransport RoundTripper = &Transport{ Proxy: ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, DualStack: true, }).DialContext, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second,} Go举荐应用field:value的复合字面值模式对struct类型变量进行值结构,这种值结构形式能够升高构造体类型使用者与构造体类型设计者之间的耦合,这也是Go语言的习用法。 这个是真的很香,Groovy和Kotlin也有相似的反对,很方便使用。尤其是构造函数特地长的时候,你可能说builder也能够做到,但谁不想少写几行代码呢。 6. 对于编程范式的反对在Java中,类是一等公民。反对继承、组合,对函数式编程有肯定的反对。在Go中,函数是一等公民(多返回值),对于函数式编程反对较为齐备。对面向对象齐全通过组合来实现。从传参是否能够传函数上,咱们就能够看出Go的反对比Java好。Java传参中,传一个函数,其实是通过一个匿名对象来传,而Go是真正的一个函数。Kotlin在这块绝对Java好了点,至多在编写时。在Java中,你想写个工具函数,也要先申明一个类再写进去。略Verbose,其实这个类咱们不会把它new进去,只是为了放个函数,所以咱们写了个类。但理论用的时候,XxxUtils.method,后面的Xxx其实有肯定的揭示作用,能够作为一个上下文来猜想外面的逻辑。然而如果咱们在method里写分明,当然也能够做到同样的效用,所以这点来说Go是比拟难受的。Go的对象办法申明形式比拟非凡://申明一个类型type MyInt int//绑定一个办法//func前面的()里,相当于申明了这个办法绑定的类型。在Go语言里叫做recevier,一个函数只能有一个recevier,且不能是指针、接口类型。//不能横跨Go包为其余包内的自定义类型定义办法。func (i MyInt) String() string { return fmt.Sprintf("%d", int(i))}//在编译期,会把办法的第一个参数变成recevier。很简略的实现。有点像Koltin中的Extension Properties。Go的Interface是隐式的,只有你实现了对应的办法,就是这个Interface的实现。这个在一开始应用的时候会很不适应,但这个松耦的一种体现——隐式的interface实现会不经意间满足依赖形象、里氏替换、接口隔离等设计准则。Go并没有继承。相似的做法叫做类型嵌入(type embedding)的形式。简略来说就是你有一个T1,T2类型,他们有各自的办法,当你申明一个T类型时并蕴含了T1,T2类型的field,那么T就领有了T1,T2的办法。这个实现确实比继承难受多了,继承很容易写出一些坏滋味的代码。这是一种委派思维的实现(delegate)。JS中原型链从表面看起来也有点像这种。Go的形式反对多返回值。这点是比拟难受的,如果在Java中要返回多个值,就要思考封装成对象了,比方Tuple2,Tuple3...之类的,这在其余的一些JVM语言中随处可见。7. 异样流:Error与ExceptionGo外面的error相当于Java的可检异样,Panic相当于Java的RuntimeException和Error。如果你感觉Go外面大量的if err != nil让代码嵌套时,能够看看一些优化if else的技巧,比方我博客里有。总的来说,像是在不同的实现做同一件事。也是个仁者见仁智者见智的事。8. 并发Java用的POSIX原语义的线程。而Go是本人实现了一套用户态的线程,或者说叫协程。POSIX原语义的线程总体来说易用性没这么好,须要牢记一些知识点才能够防止踩坑。Go在这点上比拟敌对。性能上,因为实际时个别Java会用线程池,所以创立、销毁的代价还好。其实Go也有本人的线程池,用线程去绑多个协程。但在上下文切换上,确实是POSIX原语义的线程代价会大点。为了防止一个协程把线程独占住,在编译期、以及一些规范库API上都要做周密的设计。

May 15, 2023 · 1 min · jiezi

关于go:专升本资料怎么找可以通过哪些渠道找到

统招专升本专科生每个人只有一次考试的机会,近年来越来越多的人留神到学历的重要性,报考的人也越来越多,竞争强烈。 所以想要胜利上岸,光靠靠致力可不行,领有一个好的复习资料你就胜利了一半。 随着粉丝量越来越大,各种材料要求也越来越多,为了让大家少走弯路,分享一下找材料的办法。 参考报考院校考试教材每年招生院校都会在招生简章中颁布各招生业余考试科目的参考教材和考试纲要(并不是所有院校都颁布考试纲要)。 同学们肯定要依照院校颁布的参考教材温习备考,尽管院校招生简章颁布的工夫比拟晚,但院校的参考教材个别不会有太大变动,能够先参照前一年的教材进行购买。 各平台网站查找各类资源网站、小红书、知乎、贴吧、微博等平台都能找到相干材料。网上材料十分多,但品质参差不齐还存在很多“坑”,同学们寻找时肯定要留神分别: 留神材料的省份和年份。专升本考试具备很强的地区差别,各省专升本考查侧重点、题型等都有差别,复习资料并不是通用的。 湖北省不颁布考试真题!也没有对立命题组! 湖北专升本专业课由院校自主命题,没有对立命题组,且不对外颁布试卷,不要轻易置信所谓的“历年真题”和“对立题库”! 微信群聊能够去寻找一些牢靠的专升本备考材料群,在群里,同学们能够相互分享学习材料。 一起提高你好,我是小熊,是一个爱技术然而更爱钱的程序员。上进且佛系自律的人。喜爱发小机密/臭屁又爱夸耀。 奋斗的大学,激情的当初。赚了钱买了房,写了书出了名。当过面试官,带过师傅搬过转。 大厂外来务工人员。是我,我是小熊,是不一样的烟火欢送围观。 我的博客 机智的程序员小熊 欢送珍藏

May 14, 2023 · 1 min · jiezi

关于go:defer有什么用呢

1. 简介本文将从一个资源回收问题引入,引出defer关键字,并对其进行根本介绍。接着,将具体介绍在资源回收、拦挡和解决panic等相干场景下defer的应用。 进一步,介绍defer的执行程序,以及在注册defer函数时,其参数的求值机会等相干个性。最初,重点解说defer的留神点,如在defer中函数中须要尽量避免引起panic,以及尽量避免在defer中应用闭包。 通过本文的浏览,读者将对Go语言中的defer有更深刻的理解,并且可能更加无效地应用这个关键字。 2. 问题引入开发过程中,函数可能会关上文件、建设网络连接或者其余须要手动敞开的资源。当函数在处理过程中产生谬误时,咱们须要手动开释这些资源。而如果有多处须要进行错误处理,手动开释资源将是一个不小的心智累赘。同时,如果咱们脱漏了资源的开释,就会导致资源透露的问题。这种问题可能会导致系统性能降落、程序运行异样或者零碎解体等。 以下是一个示例代码,其中函数关上了一个文件,读取其中的内容并返回: func ReadFile(filename string) ([]byte, error) { f, err := os.Open(filename) if err != nil { return nil, err } var content []byte _, err = f.Read(content) if err != nil { // 呈现谬误,此时调用Close开释资源 f.Close() return nil, err } // 失常解决完结,也须要调用Close开释资源 f.Close() return content, nil}在下面的代码中,咱们应用了 os.Open 函数关上一个文件,并在函数返回之前应用 f.Close() 函数手动敞开文件。同时,在呈现谬误时,咱们也调用了f.Close()办法手动敞开了资源。 然而,咱们构想一下,如果函数中不仅仅只关上了一个文件,而是同时关上了文件,网络连接,数据库连贯等资源,同时假如函数中须要错误处理的中央有5处,此时在错误处理中,来实现对资源的回收是十分大的心智累赘,而且一旦在某个错误处理中,遗记对资源的回收,那就代表着资源的透露,将会带来一系列的问题。而且,如果在函数执行过程中产生了panic,此时将不会执行谬误处理函数,会间接退出,函数关上的文件可能将不会被敞开。 综上所述,咱们这里遇到的问题,在于函数处理过程中,会关上一些资源,在函数退出时须要正确开释资源。而开释资源的形式,如果是在每一个错误处理处来对资源进行开释,此时对于开发人员是一个不小的累赘;同时对于函数执行过程中产生panic的状况,也无奈失常开释资源。 那有什么形式,可能简洁高效得开释资源,无需在函数的多个错误处理处都执行一次资源的回收;同时也可能解决panic可能导致资源透露的问题吗? 其实还真有,Go中的defer关键字便非常适合在该场景中应用,上面我先来理解理解defer。 3. defer对问题的解决3.1 defer根本介绍在Go语言中,咱们能够在函数体中应用 defer 关键字,来提早函数或办法的执行。defer 提早的函数或办法,会在以后函数执行完结时执行,无论函数是失常返回还是异样返回。也就是说,无论在函数中的哪个地位,只有应用了 defer 提早执行了某个函数或办法,那么这个函数或办法的执行都会被推延到以后函数执行完结时再执行。 defer 语句的语法很简略,它只须要在须要提早执行的语句前加上 defer 关键字即可。defer 语句反对执行函数调用和办法调用,也能够在语句中应用函数参数和办法参数等。上面是一个 defer 语句的示例: ...

May 14, 2023 · 2 min · jiezi

关于go:golang-微服务的负载均衡

上次咱们说了一下 微服务的容错解决,是用的 断路器 这一次咱们来一起看看 微服务的负载平衡是如何做的 负载平衡负载平衡是什么呢? 他可能将大量的申请,依据负载平衡算法,将不同的申请散发到多台服务器上进行解决,使得所有的服务器负载都维持在一个高效稳固的状态,进而能够进步零碎的吞吐量,和保证系统的可用性 例如咱们的拜访服务器是这样的 用户 – 网络 – 服务器 – 数据库 那么,如果这一个服务器的申请数很高,超过了服务器能能解决的极限,本身无奈及时响应的时候,则会出现异常,甚至无奈连贯,用户就无奈失去及时的冀望后果 那么咱们至多能够冀望服务器部署是这个样子的 就是在服务器的后面加一个负载均衡器,这样内部申请的压力就能够又 多个服务器来分担,并且申请给到任何一个服务器,失去的响应都是一样的 那么咱们一起来看看负载平衡的类型都有哪些 负载平衡的类型负载平衡的类型有 2 类: 软件负载平衡个别是独立的负载平衡软件来实现内部申请的散发,个别这样的软件配置简略,应用老本很低,并且可能满足根本的负载平衡要求,例如 haproxy 那么这就要对重点关注在软件的品质和该软件部署在所属服务器的性能下面,若软件品质不行,或者部署的服务器性能不行,都会成为零碎吞吐量的瓶颈 硬件负载平衡硬件的负载平衡,必然是依赖非凡负载平衡设施来做的,部署老本绝对较高,可是对于软件的负载平衡,硬件的做法可能满足更多种场景的应用 例如常见的例子,DNS 负载平衡 和 反向代理负载平衡 DNS 负载平衡 例如在 DNS服务器中,咱们会给一个同一个名称配置多个 IP,那么不同的 DNS 申请就会解析到不同的 IP 地址,进而这就能够达到 不同申请去拜访不同的服务器的目标,这就是咱们的 DNS 负载平衡 反向代理负载平衡 咱们平时我的项目中应用到的服务网关就是反向代理负载平衡 作为客户端,你是不晓得你拜访的这个地址是不是真正的服务器的地址,你拜访了网关地址之后,网关会依据路由将你的申请发送给对应服务器去解决,最终返回后果,例如这样 负载平衡算法如何保障可能让每一个服务器的都可能处于高效稳固的运行呢,这就须要优良的负载平衡算法出马了 负载平衡算法定义了如何将内部申请扩散到各个服务器实例中,它可能无效的进步吞吐量 个别会有这几种算法: 随机法随机从服务器集群中任选一台。这种办法的确很简略,保障了申请的分散性,可是这种办法无奈做到以后的申请调配是否正当以及不同服务器本身的负载能力 轮询或者加权轮询法就是轮流的将申请调配给集群中每一个服务器,加权的话,就是依照比例轮询的形式将申请调配给集群中的每一个服务器,如: 轮询 3 个服务器 加权轮询 3 个服务器,若 A 占比 20%,B 占比 50 % ,C 占比 30% ...

May 14, 2023 · 1 min · jiezi

关于go:如何优雅得关闭协程呢

1.简介本文将介绍首先为什么须要被动敞开goroutine,并介绍如何在Go语言中敞开goroutine的常见套路,包含传递终止信号和协程外部捕获终止信号。之后,文章列举了须要被动敞开协程运行的常见场景,如启动一个协程执行一个一直反复的工作。心愿通过本文的介绍,读者可能把握如何在适当的时候敞开goroutine,以及理解敞开goroutine的常见套路。 2.为什么须要敞开goroutine2.1 协程的生命周期理解协程的生命周期是优雅地敞开协程的前提,因为在敞开协程之前须要晓得协程的以后状态,以便采取相应的措施。所以这里咱们须要先理解下goroutine的生命周期。 在 Go语言中,协程(goroutine)是一种轻量级的线程,能够在一个程序中同时运行多个协程,进步程序的并发性能。协程的生命周期包含创立、运行和完结三个阶段。 首先须要创立一个协程,协程的创立能够通过关键字 go 来实现,例如: go func() { // 协程执行的代码}()下面的代码会启动一个新的协程,同时在新的协程中执行匿名函数,此时协程便已被创立了。 一旦协程被创立,它就会在新的线程中运行。协程的运行状态能够由 Go 运行时(goroutine scheduler)来治理,它会主动将协程调度到适当的P中运行,并确保协程的偏心调度和均衡负载。 在运行阶段,协程会一直地执行工作,直到工作实现或者遇到终止条件。在终止阶段,协程将会被回收,从而实现其整个生命周期。 综上所述,协程由go关键字启动,在协程中执行其业务逻辑,直到最初遇到终止条件,此时代表着协程的工作曾经完结了,将进入终止阶段。最终协程将会被回收。 2.2 协程的终止条件失常来说,都是协程工作执行实现之后,此时协程主动退出,例如: func main() { var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 协程执行的代码 fmt.Println("协程执行结束") }() wg.Wait() // 期待协程执行结束 fmt.Println("主程序完结")下面的代码中,咱们应用 WaitGroup 期待协程执行结束。在协程执行结束后,程序会输入协程执行结束和主程序完结两条信息。 还有一种状况是协程产生panic,它将会主动退出。例如: func main() { var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() // 协程执行的代码 panic("协程产生谬误") }() // 期待协程执行结束 wg.Wait() fmt.Println("主程序完结")}在这种状况下,协程也会主动退出,不会再占用系统资源。 综合看来,协程的终止条件,其实就是协程中的工作执行实现了,或者是执行过程中产生了panic,协程将满足终止条件,退出执行。 2.3 为什么须要被动敞开goroutine从下面协程的终止条件来看,失常状况下,协程只有将工作失常解决实现,协程主动退出,此时并不需要被动敞开goroutine。 这里先举一个生产者消费者的例子,在这个例子中,咱们创立了一个生产者和一个消费者,它们之间通过一个channel进行通信。生产者生产数据并发送到一个channel中,消费者从这个channel中读取数据并进行解决。代码示例如下: func main() { // 生产者代码 go func(out chan<- int) { for i := 0; ; i++ { select { case out <- i: fmt.Printf("producer: produced %d\n", i) time.Sleep(time.Second) } } // 消费者逻辑 go func(in <-chan int) { for { select { case i := <-in: fmt.Printf("consumer: consumed %d\n", i) } } } // 让生产者协程和消费者协程始终执行上来 time.Sleep(100000000)}在这个例子中,咱们应用了两个goroutine:生产者和消费者。生产者向channel中生产数据,消费者从channel中生产数据。 ...

May 14, 2023 · 3 min · jiezi

关于go:GoGraceful-Shutdown

Go1.8之后有了Shutdown办法,用来优雅的敞开(Graceful Shutdown)服务。 func (srv *Server) Shutdown(ctx context.Context) error这个办法会在调用时进行下述操作:1.敞开所有open listeners2.敞开所有idle connections3.无限期期待connections回归idle状态4.之后敞开服务注:3的无限期期待能够用context的超时来解决。 Go1.9之后有了RegisterOnShutdown办法,用来在优雅的敞开服务的同时解决一些退出工作。 func (srv *Server) RegisterOnShutdown(f func())对于RegisterOnShutdown如何失效,咱们看代码。 type Server struct { ... onShutdown []func()}func (srv *Server) RegisterOnShutdown(f func()) { srv.mu.Lock() srv.onShutdown = append(srv.onShutdown, f) srv.mu.Unlock()}func (srv *Server) Shutdown(ctx context.Context) error { ... srv.mu.Lock() ... for _, f := range srv.onShutdown { go f() } srv.mu.Unlock() ...}由代码可知,在通过RegisterOnShutdown进行注册之后,这些函数被放入一个函数切片中,并在Shutdown被调用的时候,为每个函数启动了一个goroutine进行解决。但因为没有进行后续解决,于是这里有个小问题,Shutdown是不期待这些处理函数完结的,就可能比这些处理函数先实现并进而完结程序。 package mainimport ( "context" "log" "net/http" "os" "os/signal" "time")func main() { var srv http.Server srv.RegisterOnShutdown(func() { time.Sleep(3 * time.Second) log.Println("Exit func") }) idleConnsClosed := make(chan struct{}) go func() { sigint := make(chan os.Signal, 1) signal.Notify(sigint, os.Interrupt) <-sigint // We received an interrupt signal, shut down. if err := srv.Shutdown(context.Background()); err != nil { // Error from closing listeners, or context timeout: log.Printf("HTTP server Shutdown: %v", err) } close(idleConnsClosed) }() if err := srv.ListenAndServe(); err != http.ErrServerClosed { // Error starting or closing listener: log.Fatalf("HTTP server ListenAndServe: %v", err) } <-idleConnsClosed}运行时Ctrl+c之后,服务立即完结了,并未期待log.Println("Exit func")的输入。 ...

May 12, 2023 · 2 min · jiezi

关于go:golang-使用-OpenTelemetry-实现跨服务-gin-echo-全链路追踪

应用 OpenTelemetry 链路追踪阐明工作中经常会遇到须要查看服务调用关系,比方用户申请了一个接口接口会调用其余grpc,http接口,或者外部的办法这样的调用链路,如果呈现了问题,咱们须要疾速的定位问题,这时候就须要一个工具来帮忙咱们查看调用链路OpenTelemetry就是这样一个工具本文大略以:main 函数初始化 OpenTelemetry、启动 http server、配置httpclient 申请服务 来进行阐明残缺可执行源码在:https://github.com/webws/go-moda/tree/main/example/tracing/moda_tracing前面会补充grpc 的链路追踪服务链路关系关系图graph LRA[用户] --> B[api1/bar]B --> C[api2/bar]C --> D[api3/bar]D --> E[bar]E --> F[bar2]F --> G[bar3]阐明:用户 申请 api1(echo server) 服务的 api1/barapi1 调用 api2 (gin server) 服务的 api2/barapi2 调用 api3 (echo server )服务的 api3/barapi3 调用 外部 调用办法 bar->bar2->bar3装置jaeger下载jaeger:我应用的是 jaeger-all-in-one启动 jaeger: ~/tool/jaeger-1.31.0-linux-amd64/jaeger-all-in-one默认查看面板 地址 http://localhost:16686/tracer Batcher的地址,上面代码会体现: http://localhost:14268/api/traces初始化 全局的 OpenTelemetry这里openTelemetry 的exporter 以 jaeger 为例,其余的exporter 能够参考官网文档 var tracer = otel.Tracer("go-moda")func InitJaegerProvider(jaegerUrl string, serviceName string) (func(ctx context.Context) error, error) { if jaegerUrl == "" { logger.Errorw("jaeger url is empty") return nil, nil } tracer = otel.Tracer(serviceName) exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(jaegerUrl))) if err != nil { return nil, err } tp := tracesdk.NewTracerProvider( tracesdk.WithBatcher(exp), tracesdk.WithResource(resource.NewSchemaless( semconv.ServiceNameKey.String(serviceName), )), ) otel.SetTracerProvider(tp) // otel.SetTextMapPropagator(propagation.TraceContext{}) b3Propagator := b3.New(b3.WithInjectEncoding(b3.B3MultipleHeader)) propagator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}, b3Propagator) otel.SetTextMapPropagator(propagator) return tp.Shutdown, nil}阐明下面办法的参数 jaegerUrl ,如果装置的是 jaeger-all-in-one,则地址默认为 http://localhost:14268/api/tracesserviceName 是服务名称,这里我应用的是 api1,api2,api3减少 span 能够应用 tracer.Start(ctx, "spanName")http服务链路追踪下面初始化了全局的 OpenTelemetry后,在以后服务就能够应用 OpenTelemetry 的 tracer 进行链路追踪了 但如果 须要跨服务进行调用,这是不够的,比方http server之间的调用,须要: ...

May 12, 2023 · 2 min · jiezi

关于go:安装go依赖包firewall网络失败问题

问题对于 golang.org 下的源码,在国内无法访问golang源。 提醒: 目前遇到这个状况应该会越来越少了,随着>=go1.14用于mod治理依赖包,很多都是应用github.com等能够间接拜访的地址域。 当然,也会遇到开源库没有改变援用的,还是会援用这个 golang.org 的就须要手动下载包了。 解决办法返回golang在github上的镜像源。镜像源地址 如何搜寻寻找依赖包呢?举例说明。寻找 golang.org/x/tools 的tools包,则在镜像源地址搜寻:tools, 另外,个别状况下,能够间接依据规定 [镜像源地址]/[包名] 间接拜访地址就行,这里就是 https://github.com/golang/tools。 找到包之后,下载到本地。形式1: 手动下载xxx.zip压缩包即可。形式2: 手动 git clone 仓库到本地即可。 下载后进行装置这些依赖包。依赖包有 func main() 入口的,须要装置go build并将可执行文件已到GOBIN环境里。没有入口的,仅仅作为依赖包 import 的,间接执行go install即可。 留神:如果装置或应用依赖包时,如果提醒依赖关系短少。解决:短少什么依赖包,便本人 go get 或 如上边操作,手动下载安装 相干依赖就行。 装置例子: # 1. 筹备,本地存储依赖包的目录GOPATH下创立好所在目录cd $GOPATH/srcmkdir -p golang.org/x# 1. 下载# 返回 https://github.com/golang , 搜寻:tools# 能够通过 git clone 下载源码包并切换tag分支版本。我这里抉择间接,点击 Release, 抉择一个版本 tools-gopls-v0.7.1.zip 下载# 切至本地此依赖包所属目录cd $GOPATH/src/golang.org/x/# 寄存离线依赖包cp -r ~/Downloads/tools-gopls-v0.7.1.zip ./# 解压unzip tools-gopls-v0.7.1.zip# 重命名,保障和导包门路统一mv tools-gopls-v0.7.1 tools# xxx.zip不想要能够删除了rm -rf tools-gopls-v0.7.1.zip# 2. 装置# 切至本地此依赖包目录cd $GOPATH/src/golang.org/x/tools/# 用于本地导包应用,执行装置go install# 到此结束

May 11, 2023 · 1 min · jiezi

关于go:Go框架深入解析gin中使用validator包对请求体进行验证

大家好,我是渔夫子。 明天给大家聊一聊gin框架中是如何解析申请中的json并对其进行验证的。 从一个示例开始在上面这个示例中,定义了一个User构造体,该构造体中有3个字段:FirstName、LastName和Email。同时定义了一个校验函数 UserStructLevelValidation ,该函数对User构造体中的字段进行了校验。如下: 校验FirstName和LastName是否为空对Email字段值进行正则校验,同时校验是否是空。代码如下: // User contains user information.type User struct { FirstName string `json:"fname"` LastName string `json:"lname"` Email string `binding:"required,email"`}func UserStructLevelValidation(sl validator.StructLevel) { user := sl.Current().Interface().(User) if len(user.FirstName) == 0 && len(user.LastName) == 0 { sl.ReportError(user.FirstName, "FirstName", "fname", "fnameorlname", "") sl.ReportError(user.LastName, "LastName", "lname", "fnameorlname", "") } // plus can to more, even with different tag than "fnameorlname"}那么问题来了: 第一:校验函数UserStructLevelValidation是如何和指标构造体User进行关联的?第二:UserStructLevelValidation是在哪里被调用的?第三:UserStructLevelValidation函数的入参为什么是validator.StructLevel类型?第四:User构造体中的Email字段是如何被校验的?第五:bingding tag都有哪些属性以及对应的含意?接下来,咱们就一一解答上述所有问题,以便对构造体的验证有一个全面的理解。 校验函数和指标构造体是如何关联的当咱们自定义了校验函数UserStructLevelValidation之后,在main函数中就能够通过以下代码和指标构造体User进行关联了: import ( "net/http" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" validator "github.com/go-playground/validator/v10")func main() { route := gin.Default() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { v.RegisterStructValidation(UserStructLevelValidation, User{}) } route.POST("/user", validateUser) route.Run(":8085")}通过代码咱们能够看到,校验函数和指标构造体是通过**v.RegisterStructValidation**函数进行关联的。该实例是将**UserStructLevelValidation**和**User**构造体进行了关联。 ...

May 10, 2023 · 1 min · jiezi

关于go:Go-121版本新特性前瞻

本文首发自「慕课网」,想理解更多IT干货内容,程序员圈内热闻,欢送关注"慕课网"! 作者:tonybai | 慕课网讲师 Go 1.21版本正在热火朝天地开发当中,依照Go外围团队的一年两次的公布节奏来算,Go 1.21版本预计将在2023年8月公布(Go 1.20版本是在2023年2月份公布的)。 本文将和大家一起看看Go 1.21都会带来哪些新个性。不过因为目前为时尚早,上面列出的有些变动最终不肯定能进入到Go 1.21的最终版本中,所以切记所有变更要以最终Go 1.21版本公布时为准。 在细数变动之前,咱们先来看看Go语言的以后状态。 1. Go语言以后状态Go语言的2022年初排名为12位,同时TIOBE官网编辑也提到:“在新兴编程语言中,Go是惟一一个可能在将来冲入前十的后端编程语言”。Go语言的倒退仿佛应验了这一预测,在往年的3月份,Go就再次进入编程语言排行榜前十: 一个月后的四月初,TIOBE排行榜上,Go稳住了第10名的位次: 在国内,在鹅厂前不久公布的《2022年腾讯研发大数据报告》中,在国内,继Go在2021年从C++手中躲过红旗首次登顶鹅厂最热门编程语言之后,在鹅厂前不久公布的《2022年腾讯研发大数据报告》中,Go蝉联鹅厂最热门编程语言,持续夯实在国内头部互联网公司内的劣势位置: Go于2009年开源,在经验多年的宣传和宣扬后,Go目前进入了安稳倒退的阶段。疫情完结后,原先线上举办或勾销的国内外的Go技术大会当初陆续又都开始复原了,置信这会让更多开发人员接触到Go。像Go这样的能在世界各地继续多年举办技术大会的语言真是不多了。接下来,咱们就来聚焦到Go 1.21版本,开掘一下这个版本都有哪些新个性。 2. 语言变动目前Go 1.21版本里程碑中波及语言变动的有大概2项,咱们来看看。 2.1 减少clear预约义函数 Go 1.21减少了一个clear预约义函数用来做切片和map的clear操作,其原型如下: // $GOROOT/src/builtin.go// The clear built-in function clears maps and slices.// For maps, clear deletes all entries, resulting in an empty map.// For slices, clear sets all elements up to the length of the slice// to the zero value of the respective element type. If the argument// type is a type parameter, the type parameter's type set must// contain only map or slice types, and clear performs the operation// implied by the type argument.func clear[T ~[]Type | ~map[Type]Type1](t T)clear是针对map和slice的操作函数,它的语义是什么呢?咱们通过一个例子来看一下: ...

May 10, 2023 · 3 min · jiezi

关于go:Go-语言基础之-Context-详解

之前有兄弟留言想学习一下 Context,他来了,虽迟但到。 前言在 Go 语言中,Context 是一个十分重要的概念,它用于在不同的 goroutine 之间传递申请域的相干数据,并且能够用来管制 goroutine 的生命周期和勾销操作。本文将深入探讨 Go 语言中 Context 个性 和 Context 的高级应用办法。 根本用法在 Go 语言中,Context 被定义为一个接口类型,它蕴含了三个办法: # go version 1.18.10type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key any) any}Deadline() 办法用于获取 Context 的截止工夫,Done() 办法用于返回一个只读的 channel,用于告诉以后 Context 是否曾经被勾销,Err() 办法用于获取 Context 勾销的起因,Value() 办法用于获取 Context 中保留的键值对数据。咱们日常编写代码时,Context 对象会被被约定作为函数的第一个参数传递,eg: func users(ctx context.Context, request *Request) { // ... code}在函数中,能够通过 ctx 参数来获取相干的 Context 数据,举个超时的 eg: ...

May 10, 2023 · 3 min · jiezi

关于go:Go1204-新版本发布修复了一个神奇的内联-BUG

大家好,我是煎鱼。 最近 Go 在劳动节期间,Go 公布了小版本的版本更新,次要是 Go1.20.4 和 Go1.19.9: 周末我在看 Go1.20.4 的公布里程碑记录时,发现了一个比拟有意思的 BUG,继续了很久,始终没人发现。直至今日才被修复。 咱们疾速来看一下。 演示代码如下: package mainfunc foo() { println("foo")}func main() { fn := foo for _, fn = range list { fn() }}var list = []func(){ func() { println("1") }, func() { println("2") }, func() { println("3") },}请问运行的后果是什么? 我掐指一算,是如下后果: 123对吗? 不不不,其实运行后果是: foofoofoo这 “误会” 可大了。为什么呢?能够通过内联剖析看到 Go 程序外部的剖析: go run -gcflags='-m=1' a.go# command-line-arguments./a.go:3:6: can inline foo./a.go:7:6: can inline main./a.go:10:5: inlining call to foo./a.go:15:2: can inline glob..func1./a.go:18:2: can inline glob..func2./a.go:21:2: can inline glob..func3实质上就是内联函数的后果是谬误的,与咱们所编写的 Go 程序的预期不统一,呈现暗藏的 BUG(要是踩坑了,预计要排查很久,会先狐疑是不是本人写出了 BUG...)。 ...

May 9, 2023 · 1 min · jiezi

关于go:Golang底层实现系列syncMap底层实现

[最初更新日期:2023-05-08 18:04] Go中一般的map是非线程平安的,想要线程平安的拜访一个map,有两种形式一种是map+mutex另一种就是原生的sync.Map,这篇文章会具体的介绍sync.Map底层是如何实现的,以及一些罕用的场景。 如何保障线程平安?sync.Map的数据结构如下: type Map struct { mu Mutex // 锁,保障写操作及dirty晋升为read的线程平安 read atomic.Value // readOnly 只读map dirty map[any]*entry // 脏map,当外部有数据时就肯定蕴含read中的数据 misses int // read未命中次数,当达到肯定次数时会触发dirty中的护具降职到read}如果只看这个构造咱们可能会有以下几个疑难: sync.Map中也用了mutex那和map+mutex的实现形式不就一样了吗?misses做什么用的?read的类型是一个atomic.Value而dirty是map[any]*entry,为什么不同?sync.Map中也用了mutex那和map+mutex的实现形式不就一样了吗?在实质上都是通过map+mutex的实现形式来实现的sync.Map通过减少read map,升高在进行读取操作时的加锁概率,减少读取的性能。misses做什么用的?misses是用于标记read中未命中次数的当misses达到肯定值时会触发dirty的降职(晋升为read)具体源码如下: // 当执行Load操作时没能在read中命中key,则进行一次miss记录func (m *Map) missLocked() { // 1.miss计数加1 m.misses++ // 2.判断dirty是否满足降职条件 if m.misses < len(m.dirty) { // 2.1不满足间接返回 return } // 3.将dirty中的数据转存到read的m中,旧的read中的数据被摈弃 m.read.Store(readOnly{m: m.dirty}) // 4.清空dirty m.dirty = nil // 5.重置miss计数 m.misses = 0}从代码中能够看到: 当misses值大于等于dirty中数据个数的时候会触发dirty的降职在dirty降职时,直间接把read重置成了一个新生成的readOnly,其中m为新的dirty,amended为默认值false,保障每次触发降职都主动将amended设置为了false在dirty降职时,并没有触发数据的拷贝read的类型是一个atomic.Value而dirty是map[any]*entry,为什么不同?type readOnly struct { m map[any]*entry // read map中的数据 amended bool // 标记dirty map中是否有read中没有的key,如果有,则此值为true}type entry struct { p unsafe.Pointer // *interface{} 一个指向具体数据的指针}read的类型底层是存储的readOnly类型,而readOnly类型只是在map[any]*entry的根底上减少了一个amended标记如果amended为false,则代表dirty中没有read中没有的数据,此时能够防止一次dirty操作(会加锁),从而升高无意义的加锁。read被申明为atomic.Value类型是为了满足在无锁的状况下多个Goroutine同时读取read时的数据一致性sync.Map实用于那些场景?sync.Map更适宜读多写少的场景,而当map须要频繁写入的时候,map+mutex的计划通过管制锁的力度能够达到比sync.Map更好的性能。 ...

May 8, 2023 · 3 min · jiezi

关于go:为什么需要超时控制

# 1. 简介 本文将介绍为什么须要超时管制,而后具体介绍Go语言中实现超时管制的办法。其中,咱们将探讨time包和context包实现超时管制的具体形式,并阐明两者的实用场景,以便在程序中以更适合的形式来实现超时管制,进步程序的稳定性和可靠性。 2. 为什么须要超时管制超时管制能够帮忙咱们防止程序无限期地期待某个操作实现或者避免程序因为某些起因导致资源透露。具体来说,超时管制有以下几个长处: 防止无限期期待:如果某个操作须要期待一段时间,但如果超过了这个工夫还没有实现,那么程序可能就须要进行期待并采取其余措施,比方返回谬误或者勾销操作。超时解决能够让程序防止无限期期待,从而进步程序的健壮性和可靠性。避免资源透露:如果程序某个操作始终处于期待状态,那么可能会导致资源被始终占用,从而造成资源透露。超时管制能够让程序在肯定工夫内实现操作,如果超时则开释资源,从而防止资源透露。进步程序响应速度:有些操作可能须要很长时间能力实现,这可能会导致程序在期待过程中变得不响应。超时管制能够让程序在肯定工夫内实现操作,如果超时则采取其余措施,从而进步程序的响应速度。基于以上几点起因,咱们能够看进去,在某些场景下,超时管制在程序执行过程中必不可少。那么,在Go语言中,有哪些形式能够实现超时管制呢? 3. 超时管制的办法 3.1 time包实现超时管制    time包提供了多种形式来实现超时管制,包含time.After函数、time.NewTimer函数以及time.AfterFunc函数,应用它们能够实现超时管制,上面以time.NewTimer函数为例,阐明如何应用其time包实现超时管制。代码示例如下: // 创立一个定时器timer := time.NewTimer(5 * time.Second)defer timer.Stop()// 应用一个channel来监听工作是否已实现ch := make(chan string, 1) go func() { // 模仿工作执行,休眠5秒 time.Sleep(2* time.Second) ch <- "hello world" }()// 通过select语句来期待后果,工作失常返回select {case <-ch: fmt.Println("工作失常实现") // ch 曾经接管到值,走失常解决逻辑case <-timer.C: fmt.Println("已超时") // 超时,走超时逻辑}在这里例子中,咱们应用 time.NewTimer 办法创立一个定时器,超时工夫为2秒钟。而后在 select 语句中应用来期待后果,哪个先返回就应用哪个。 如果操作在2秒钟内实现,那么工作失常实现;如果操作超过2秒钟仍未实现,此时select语句中<-timer.C将接管到值,走超时解决逻辑。 3.2 context实现超时管制Context 接口是 Go 语言规范库中提供的一个上下文(Context)管理机制。它容许在程序的不同局部之间传递上下文信息,并且能够通过它实现超时管制、勾销操作以及截断操作等性能。其中,Context接口存在一个timerCtx的实现,其能够设定一个超时工夫,在达到超时工夫后,timerCtx对象的 done channel 将会被敞开。 当须要判断是否超时时,只须要调用 context 对象的 Done 办法,其会返回timerCtx对象中的done channel,如果有数据返回,则阐明曾经超时。基于此,咱们便能够实现超时管制。代码示例如下: // 创立一个timerCtx,设置超时工夫为3秒 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) // 调用cancel函数,开释占用的资源 defer cancel()// 应用一个channel来监听工作是否已实现ch := make(chan string, 1) go func() { // 模仿工作执行,休眠5秒 time.Sleep(2* time.Second) ch <- "hello world" }()// 通过select语句来期待后果,工作失常返回select { case <-ctx.Done(): fmt.Println("timeout") case result := <-ch: fmt.Println(result)}这里通过context.WithTimeout创立一个timerCtx,设定好超时工夫,超时工夫为3s。而后启动一个协程来执行具体的业务逻辑。 ...

May 7, 2023 · 2 min · jiezi

关于go:Golang-实现与-cryptojs-一致的-AES-简单加解密

前言最近始终在折腾 Golang 的 AES 加密解密,最后的一个小需要只是寻求一个简略间接的加密工具而已,然而找着找着发现外面的坑太深了... 吐槽:对于加密解密,其实咱们很多时候并没有特地高的要求(简单)。一开始,我最间接的一个想法就是: 调用一个办法,传递一个秘钥,实现加密;调用一个办法,传递一个秘钥,实现解密,就能够了,但事实网上纷繁复杂的实现让我头疼。难道,就没有一个让我最省心、简略、最快、实现一个加解密的办法吗? 指标我要一个对称加密,加解密用的 key 统一加密后的数据 = 加密办法(数据, key)解密后的数据 = 解密办法(数据, key)仅此而已,但寻变网络各种类库,没意外,各有各的问题,上面我列举几个我在做的过程中遇到的问题和坑问题AES 有各种加密模式 CBC、ECB、CTR、OCF、CFB 选哪个?都平安吗?AES 在某些加密模式下须要指定 IV 也就是初始向量(那我岂不是又要弄一个配置项?)AES 对于 key 的长度 和 IV 的长度都有要求 (这个很烦,就像我定一个明码还非得是固定长度的)AES 须要加密的数据不是16的倍数的时候,须要对原来的数据做padding操作(能够简略了解为补充长度到固定的位数)好嘛,padding还有不同的形式:Zero padding、ANSI X.923、PKCS7...js 罕用 crypto-js 进行加密解密操作(我这边还想有个特地需要能保障 js 加密统一)上代码show me your code 先来看下最终实现状况如何,而后再来说原理和问题Golang 实现package mainimport ( "fmt" "github.com/LinkinStars/go-scaffold/contrib/cryptor")func main() { key := "1234" e := cryptor.AesSimpleEncrypt("Hello World!", key) fmt.Println("加密后:", e) d := cryptor.AesSimpleDecrypt(e, key) fmt.Println("解密后:", d) iv := cryptor.GenIVFromKey(key) fmt.Println("应用的 IV:", iv)}// 输入// 加密后: NHlpzbcTvOj686VaF7fU7g==// 解密后: Hello World!// 应用的 IV: 03ac674216f3e15c对,这就是我想要的,输出须要加密的内容和 key,给我出加密后的后果就好crypto-js 实现解密也是相似的,这里我就不反复代码了import CryptoJS from 'crypto-js'var data = "Hello World!"var keys = [ "1234", "16bit secret key", "16bit secret key1234567", "16bit secret key12345678", "16bit secret key16bit secret ke", "16bit secret key16bit secret key", "16bit secret key16bit secret key1",]function aesEncrypt(data, key) { if (key.length > 32) { key = key.slice(0, 32); } var cypherKey = CryptoJS.enc.Utf8.parse(key); CryptoJS.pad.ZeroPadding.pad(cypherKey, 4); var iv = CryptoJS.SHA256(key).toString(); var cfg = { iv: CryptoJS.enc.Utf8.parse(iv) }; return CryptoJS.AES.encrypt(data, cypherKey, cfg).toString();}for (let i = 0; i < keys.length; i++) { console.log(aesEncrypt(data, keys[i]))}// 输入// NHlpzbcTvOj686VaF7fU7g==// PuMhKY8ZFLnDAwlQ7v/2SQ==// ZG9JUBvEXrXwSS2RIHvpog==// pbvDuBOV3tJrlPV0xdmbKQ==// uAeg71zBzFeUfEMHJqCSxw==// j9SbFFEEFX4dT9VaDAzsCg==// j9SbFFEEFX4dT9VaDAzsCg==问题与解决方案抉择什么加密模式加密模式有 CBC、ECB、CTR、OCF、CFB,其中 ECB 有平安问题,所以肯定不抉择,而罕用的是 CBC,并且 crypto-js 默认也用了 CBC 所以就无脑抉择了 CBC ...

May 5, 2023 · 3 min · jiezi

关于go:OpenTelemetry入门

步骤装置OpenTelemetry分为两局部:用于追踪代码的API和SDKAPI局部: go get go.opentelemetry.io/otel \ go.opentelemetry.io/otel/traceSDK局部: go get go.opentelemetry.io/otel/sdk \ go.opentelemetry.io/otel/exporters/stdout/stdouttrace设置应用程序的名称// name is the Tracer name used to identify this instrumentation library.const name = "fib"代码监测 - 创立span//创立指定应用程序的追踪器otel.Tracer(name) //创立span newCtx, span := otel.Tracer(name).Start(ctx, "办法名")defer span.End()示例: func Create(w http.ResponseWriter, r *http.Request) { ctx := context.Background() newCtx, span := otel.Tracer(name).Start(ctx, "Create") defer span.End() time.Sleep(5 * time.Second) GetOne(newCtx, r.URL.Query().Get("mobile"))}func GetOne(ctx context.Context, nStr string) { nCtx, span := otel.Tracer(name).Start(ctx, "GetOne") defer span.End() SetAge(nCtx, "hello world") span.SetAttributes(attribute.String("request.n", nStr))}func SetAge(ctx context.Context, val string) { _, span := otel.Tracer(name).Start(ctx, "SetAge") defer span.End() span.SetAttributes(attribute.String("ageTime", val))}以上他们的关系:Create├── GetOne └── SetAge创立导出器顾名思义,就是将收集的span数据导出到指定地位。比方文件,或者https://pkg.go.dev/go.opentelemetry.io/otel/exporters/jaeger,https://pkg.go.dev/go.opentelemetry.io/otel/exporters/zipkin,https://pkg.go.dev/go.opentelemetry.io/otel/exporters/prometheus等风行的开源监测工具。 ...

May 5, 2023 · 10 min · jiezi

关于go:go-协程操作map导致的数据竞争及解决方法

原文链接:何晓东 博客 场景有个查问后果集的操作,无可避免的须要在循环获取数据,而后将后果集放到 map 中,这个操作在压测的时候,没呈现问题,公布到生产环境之后,开始偶现 fatal error: concurrent map read and map write 谬误,导致容器重启了。 起因多个协程同时对 map 进行读写操作,导致数据竞争测试环境压测未复现是因为单个 pod 惯例工夫只有一个 CPU,资源不够用了才会应用两个 CPU,单核的状况下,协程是串行执行的,所以没有呈现数据竞争的问题。同时也没开着数据竞争检测,也没有检测进去这个问题 调试在本机多核CPU状况下,执行 go run --race main.go 启动我的项目,调用办法,会有提醒 data race,再开始对应解决问题。 解决方案① 应用 sync.Mutex/sync.RWMutex 加锁互斥锁:Mutex是互斥锁的意思,也叫排他锁,同一时刻一段代码只能被一个线程运行,应用只须要关注办法Lock(加锁)和Unlock(解锁)即可。在Lock()和Unlock()之间的代码段称为资源的临界区(critical section),是线程平安的,任何一个工夫点都只能有一个goroutine执行这段区间的代码。Mutex在大量并发的状况下,会造成锁期待,对性能的影响比拟大。 读写锁:读写锁的读锁能够重入,在曾经有读锁的状况下,能够任意加读锁。在读锁没有全副解锁的状况下,写操作会阻塞直到所有读锁解锁。写锁定的状况下,其余协程的读写都会被阻塞,直到写锁解锁。 依据业务场景,按需进行加锁,尽量减少锁的粒度,进步性能。 ② 应用 sync.Mapgo 原生的 map 不是线程平安的,sync.Map 是线程平安的,读取,插入,删除也都放弃着常数级的工夫复杂度。并且它通过空间换工夫的形式,应用 read 和 dirty 两个 map 来进行读写拆散,升高锁工夫来提高效率。 sync.Map 实用于读多写少的场景,如果并发写多的场景,还是须要加锁的对于写多的场景,会导致 read map 缓存生效,须要加锁,导致抵触变多;而且因为未命中 read map 次数过多,导致 dirty map 晋升为 read map,这是一个 O(N) 的操作,会进一步升高性能。 ③ 应用 channel 通道传递数据channel 是 goroutine 之间的通信形式,能够用来传递数据,也能够用来传递信号,比方完结信号,超时信号等。go 的一个准则也是:通过通信来共享内存,而不是通过共享内存来通信。channel 也是线程平安的,能够用来解决数据竞争的问题。 ...

May 4, 2023 · 1 min · jiezi

关于go:使用dubbogo框架的go程序可以部署到SAE吗

阿里云 Serverless 和 SAE 都是 PaaS 平台,然而针对的利用场景和应用的技术栈可能不同,导致互不兼容。目前,SAE 平台反对的是 Dubbo 服务框架的 Java 版本。 残缺内容请点击下方链接查看: https://developer.aliyun.com/ask/495440?utm_content=g_1000371193 版权申明:本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。

May 4, 2023 · 1 min · jiezi

关于go:Go语言-二进制与十进制互转代码实践

最近在备考软考的软件设计师考试,在学习过程遇到很多于计算机根底计算相干的知识点,正好最近在学Go语言,所以就把计算的形式用Go语言实现一下。以后还在学习过程中,如有问题,欢送大佬们斧正 ## 二进制转十进制 /* 转换规则: 11001 从开端到结尾,以2为底数,从0开始递增为指数 * 二进制数,而后将这些二进制数相加即可得出10进制数 11001 = 1 * 2^0 + 0 * 2^1 + 0 * 2^2 + 1 * 2^3 + 1 * 2^4 = 1 + 0 + 0 + 8 + 16 = 25 这个规定也实用于其余进制转换为十进制,只须要把底数替换为相应的进制数即可,这种办法叫做 “按权开展法" 留神: 二进制数也有小数点,区别是小数点右边的指数为负数,左边的指数为正数 例如: 11.01 = 1 * 2^-2 + 0 * 2^-1 + 1 * 2^0 + 1 * 2^1 = 0.25 + 0 + 1 + 2 = 3.25*/func binaryToDecimal(val string) string { // 获取二进制字符字符串 // 应用前可应用正则校验 [0-1]|[0-1].[0-1] var text = val // 指数 v1 var v1 float64 = 0 var len = len(text) // 查看是否蕴含小数点 contains := strings.Contains(text, ".") if contains { index := strings.LastIndex(text, ".") if index == (len -1) { text = text[0 : len-1] } else { v3 :=len - index v3-- v1 = float64(0 - v3) } } fmt.Println(v1) // 后果 var result float64 for i := len -1; i >= 0; i-- { u := string(text[i]) if u == "." { continue } v2,error := strconv.ParseFloat(u, 64) if error != nil { fmt.Println("转换失败",error) } // 乘数 pow := math.Pow(2, v1) // 数值累加 result = result + (v2 * pow) // 指数递增 v1++ } // 这里有个BUG,未判断得出的十进制数小数点前面有几位小数 return strconv.FormatInt(int64(result), 10)}十进制转二进制/* 十进制转 二进制的办法 十进制数除以2取余数法 */func decimalToBinary(val string) string { number, err := strconv.ParseInt(val, 10, 64) if err != nil { fmt.Println("数字转换失败",err) return "" } // 查看数字是否是正数 var bool = number < 0 if bool { number = 0 -number } var result = "" for true { if number == 1 { result = fmt.Sprint(result,number) break } //// 除数 var v1 = number / 2 //// 余数 var v2 = number % 2 // 取余数,拼接二进制数 result = fmt.Sprint(result,v2) number = v1 } // 反转字符串 var finalResult = "" var len = len(result) for i := len - 1; i >= 0; i-- { finalResult = fmt.Sprint(finalResult,string(result[i])) } // 如果是正数,则减少符号 if bool { finalResult = fmt.Sprint("-",finalResult) } return finalResult}总结R进制转十进制数的办法叫做按权开展法,这个权指的是指数指数在小数点左边为正数,右边为负数 例如 二进制数 "1110.01" 的指数顺次为 -2 -1 0 1 2 3欢送各位大佬斧正

May 2, 2023 · 2 min · jiezi

关于go:Go并发编程发生死锁活锁的案例分析

什么是死锁、活锁什么是死锁:就是在并发程序中,两个或多个线程彼此期待对方实现操作,从而导致它们都被阻塞,并无限期地期待对方实现。这种状况下,程序会卡死,无奈继续执行。 什么是活锁:就是程序始终在运行,然而无奈获得停顿。例如,在某些状况下,多个线程会抢夺同一个资源,而后每个线程都会开释资源,以便其余线程能够应用它。然而,如果没有正确的同步,这些线程可能会同时尝试获取该资源,而后再次开释它。这可能导致线程在有限循环中运行,却无奈获得停顿。 产生死锁的案例剖析编写会产生死锁的代码:package mainimport ( "fmt" "sync")func main() { var mu sync.Mutex mu.Lock() defer mu.Unlock() wg := sync.WaitGroup{} wg.Add(1) go func() {  fmt.Println("goroutine started")  mu.Lock() // 在这里获取了锁  fmt.Println("goroutine finished")  mu.Unlock()  wg.Done() }() wg.Wait()}运行和输入: [root@workhost temp02]# go run main.go goroutine startedfatal error: all goroutines are asleep - deadlock! # 谬误很显著了,通知你死锁啦!goroutine 1 [semacquire]:sync.runtime_Semacquire(0xc000010030?)        /usr/local/go/src/runtime/sema.go:62 +0x27......下面的代码,应用 sync.Mutex 实现了一个互斥锁。主 goroutine 获取了锁,并启动了一个新的 goroutine。新 goroutine 也尝试获取锁来执行其工作。然而,因为主 goroutine 没有开释锁,新 goroutine 将始终期待锁,导致死锁。 代码革新在下面的代码中,能够通过将主 goroutine 中的 defer mu.Unlock() 移到 goroutine 函数中的 mu.Unlock() 前面来解决问题。这样,当 goroutine 获取到锁后,它能够在实现工作后开释锁,以便主 goroutine 能够继续执行。 革新后的代码: package mainimport ( "fmt" "sync")func main() { var mu sync.Mutex mu.Lock() wg := sync.WaitGroup{} wg.Add(1) go func() {  fmt.Println("goroutine started")  mu.Lock() // 在这里获取了锁  fmt.Println("goroutine finished")  mu.Unlock()  wg.Done() }() mu.Unlock() // 开释锁 wg.Wait()}运行和输入: [root@workhost temp02]# go run main.go goroutine startedgoroutine finished如何防止死锁在 Go 语言中,要防止死锁,肯定要分明以下几个规定: 防止嵌套锁:在应用多个锁时,确保它们的嵌套程序雷同。否则,可能会呈现循环期待的状况,导致死锁。防止有限期待:如果在获取锁时指定了超时工夫,确保在超时后可能处理错误或执行其余操作。防止适度竞争:如果多个协程须要拜访雷同的资源,请确保它们不会相互烦扰。能够应用互斥锁或读写锁等机制来解决竞争问题。应用通道:Go 语言中的通道能够用于协调并发操作。应用通道来传递音讯和同步操作,能够防止死锁和竞争问题。确保资源开释:在应用锁或其余资源时,肯定要确保它们在应用后失去开释,否则可能会导致死锁。应用 select 语句:在应用通道进行并发操作时,能够应用 select 语句来防止死锁。通过 select 语句抉择多个通道中的一个进行操作,能够防止在某个通道被阻塞时呈现死锁。发生存锁的案例剖析编写会发生存锁的代码:package mainimport ( "fmt" "sync")func main() { var wg sync.WaitGroup var mu sync.Mutex var flag bool wg.Add(2) // goroutine 1 go func() {  // 先获取锁资源  fmt.Println("goroutine 1 获取 mu")  mu.Lock()  defer mu.Unlock()  // 而后期待 flag 变量的值变为 true  fmt.Println("goroutine 1 期待标记")  for !flag {   // 一直循环期待  }  // 最终输入并开释锁资源  fmt.Println("goroutine 1 从期待中开释")  wg.Done() }() // goroutine 2 go func() {  // 先获取锁资源  fmt.Println("goroutine 2 获取 mu")  mu.Lock()  defer mu.Unlock()  // 而后期待 flag 变量的值变为 true  fmt.Println("GoRoutine2 期待标记")  for !flag {   // 一直循环期待  }  // 最终输入并开释锁资源  fmt.Println("GoRoutine 2 从期待中开释")  wg.Done() }() // 在主线程中期待 1 秒钟,以便两个 goroutine 开始期待 flag 变量的值 // 而后将 flag 变量设置为 true // 因为两个 goroutine 会同时唤醒并尝试获取锁资源,它们会互相期待 // 最终导致了活锁问题,它们都无奈向前推动 fmt.Println("主线程休眠 1 秒") fmt.Println("两个goroutine都应该期待标记") flag = true wg.Wait() fmt.Println("所有 GoRoutines 已实现")}运行和输入: [root@workhost temp02]# go run main.go 主线程休眠 1 秒两个goroutine都应该期待标记goroutine 2 获取 muGoRoutine2 期待标记GoRoutine 2 从期待中开释goroutine 1 获取 mugoroutine 1 期待标记goroutine 1 从期待中开释所有 GoRoutines 已实现下面的代码存在活锁问题。如果两个goroutine同时期待flag变为true并且都曾经获取了锁资源,那么它们就会进入一个死循环并互相期待,无奈持续向前推动。 代码革新革新后的代码: package mainimport ( "fmt" "runtime" "sync")func main() { var wg sync.WaitGroup var mu sync.Mutex var flag bool wg.Add(2) // goroutine 1 go func() {  // 先获取锁资源  fmt.Println("goroutine 1 获取 mu")  mu.Lock()  defer mu.Unlock()  // 而后期待 flag 变量的值变为 true  fmt.Println("goroutine 1 期待标记")  for !flag {   runtime.Gosched() // 让出工夫片  }  // 最终输入并开释锁资源  fmt.Println("goroutine 1 从期待中开释")  wg.Done() }() // goroutine 2 go func() {  // 先获取锁资源  fmt.Println("goroutine 2 获取 mu")  mu.Lock()  defer mu.Unlock()  // 而后期待 flag 变量的值变为 true  fmt.Println("GoRoutine2 期待标记")  for !flag {   runtime.Gosched() // 让出工夫片  }  // 最终输入并开释锁资源  fmt.Println("GoRoutine 2 从期待中开释")  wg.Done() }() // 在主线程中期待 1 秒钟,以便两个 goroutine 开始期待 flag 变量的值 // 而后将 flag 变量设置为 true // 因为两个 goroutine 会同时唤醒并尝试获取锁资源,它们会互相期待 // 最终导致了活锁问题,它们都无奈向前推动 fmt.Println("主线程休眠 1 秒") fmt.Println("两个goroutine都应该期待标记") flag = true wg.Wait() fmt.Println("所有 GoRoutines 已实现")}革新后的代码在期待flag变量的循环中退出了让出工夫片的函数 runtime.Gosched(),这样两个goroutine在期待期间能够放弃工夫片,以便其余goroutine能够执行并取得锁资源。这种形式能够无效地缩小竞争水平,从而防止了活锁问题。 如何防止发生存锁的可能性在 Go 语言的并发编程中,防止活锁的要害是正确地实现同步机制。以下是一些防止活锁的办法: 防止忙期待:应用 sync.Cond 或者 channel 等同步机制来实现期待。这样防止了线程始终占用 CPU 资源而无奈获得停顿的问题。防止死锁:死锁往往是活锁的前提,因而正确地应用锁和同步机制能够防止死锁,从而防止活锁。缩小锁的粒度:尽可能将锁的粒度放大到最小范畴,防止锁住不必要的代码块。采纳超时机制:应用 sync.Mutex 的 TryLock() 办法或者应用 select 语句实现期待超时机制,这样能够避免线程无限期期待。正当设计并发模型:正当设计并发模型能够防止竞争和饥饿等问题,进而防止活锁的产生。本文转载于WX公众号:不背锅运维(喜爱的盆友关注咱们):https://mp.weixin.qq.com/s/gylcUAOWUkoB7zlve1mAoA

May 2, 2023 · 1 min · jiezi

关于go:为什么-Go-forrange-的-value-值地址每次都一样

原文链接: 为什么 Go for-range 的 value 值地址每次都一样? 循环语句是一种罕用的控制结构,在 Go 语言中,除了 for 关键字以外,还有一个 range 关键字,能够应用 for-range 循环迭代数组、切片、字符串、map 和 channel 这些数据类型。 然而在应用 for-range 循环迭代数组和切片的时候,是很容易出错的,甚至很多老司机一不小心都会在这里翻车。 具体是怎么翻的呢?咱们接着看。 景象先来看两段很有意思的代码: 有限循环如果咱们在遍历数组的同时向数组中增加元素,是否失去一个永远都不会进行的循环呢? 比方上面这段代码: func main() { arr := []int{1, 2, 3} for _, v := range arr { arr = append(arr, v) } fmt.Println(arr)}程序输入: $ go run main.go1 2 3 1 2 3上述代码的输入意味着循环只遍历了原始切片中的三个元素,咱们在遍历切片时追加的元素并没有减少循环的执行次数,所以循环最终还是停了下来。 雷同地址第二个例子是应用 Go 语言常常会犯的一个谬误。 当咱们在遍历一个数组时,如果获取 range 返回变量的地址并保留到另一个数组或者哈希时,会遇到令人困惑的景象: func main() { arr := []int{1, 2, 3} newArr := []*int{} for _, v := range arr { newArr = append(newArr, &v) } for _, v := range newArr { fmt.Println(*v) }}程序输入: ...

April 30, 2023 · 2 min · jiezi

关于go:go中间件

中间件的原理:中间件的基本原理是拦挡和解决申请,而后将申请传递给下一个处理程序(中间件或理论的申请处理函数)。它容许在申请解决流程中插入自定义逻辑。中间件能够在解决申请之前执行某些操作(预处理),也能够在解决申请之后执行某些操作(后处理)。 在Go语言中,中间件通常示意为一个函数,该函数承受一个处理程序作为参数并返回一个新的处理程序。新的处理程序能够在执行原始处理程序之前和之后执行其余操作。这样,中间件能够链接在一起,造成一个解决链,申请沿着这个链顺次传递,直到最初一个处理程序实现解决。 实现一个中间件:以下是应用Go规范库net/http实现一个简略中间件的示例。在这个示例中,咱们创立了一个申请日志记录中间件,它会在解决申请之前记录申请信息,而后将申请传递给下一个处理程序。 gopackage mainimport ( "fmt" "net/http" "time")// 日志记录中间件func Logger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 记录申请开始工夫 startTime := time.Now() // 解决申请 next.ServeHTTP(w, r) // 计算申请解决工夫并输入日志 duration := time.Since(startTime) fmt.Printf("%s %s %v\n", r.Method, r.URL.Path, duration) })}// 示例申请处理函数func helloHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, world!"))}func main() { // 创立一个新的路由处理器 mux := http.NewServeMux() // 注册申请处理函数,并将中间件利用于该处理函数 mux.Handle("/", Logger(http.HandlerFunc(helloHandler))) // 启动HTTP服务器 http.ListenAndServe(":8080", mux)}在这个示例中,咱们定义了一个日志记录中间件Logger。它承受一个http.Handler类型的参数(next),并返回一个新的http.Handler实例。新的处理程序首先记录申请的开始工夫,而后调用next.ServeHTTP(w, r)执行下一个处理程序(原始处理程序或其余中间件)。申请解决实现后,计算申请解决工夫并输入日志。 在main()函数中,咱们应用http.NewServeMux()创立一个新的路由处理器,并应用mux.Handle("/", Logger(http.HandlerFunc(helloHandler)))将日志记录中间件利用于helloHandler处理函数。这样,在解决来自客户端的申请时,申请首先通过日志记录中间件,而后才达到helloHandler。

April 27, 2023 · 1 min · jiezi

关于go:Go中timerate的使用与实现

限流常见的限流算法固定窗口计数器算法固定窗口计数器算法将工夫分为固定大小的窗口,例如1秒。在每个窗口中,服务会记录它接管到的申请数。如果在一个窗口中的申请数超过了事后设定的阈值,那么新的申请将被回绝,直到进入下一个窗口。 这种算法简略易实现,但可能会导致窗口边界左近的申请突发。例如,如果窗口大小为1秒,阈值为100,那么在1秒的边界处,服务可能会在短时间内解决200个申请。 滑动窗口计数器算法滑动窗口计数器算法试图解决固定窗口计数器算法中的申请突发问题。它将窗口分成更小的子窗口,例如将1秒分为10个100毫秒的子窗口。每次接管到申请时,服务会更新以后子窗口的计数器。服务会查看过来的N个子窗口的计数器之和,如果这个和超过阈值,那么新的申请将被回绝。 这种算法能够更好地平滑申请流量,但实现起来绝对简单,因为须要跟踪多个子窗口的计数器。 令牌桶算法令牌桶算法保护一个令牌桶,其中蕴含肯定数量的令牌。令牌以恒定速率增加到桶中,直到达到桶的容量。每次接管到申请时,服务会尝试从桶中获取一个令牌。如果桶中有足够的令牌,申请被容许解决;如果没有足够的令牌,申请将被回绝。 令牌桶算法容许短暂的申请突发,因为在低流量期间,令牌能够累积到桶的容量。这种算法在实践中体现良好,但实现起来绝对简单。 漏桶算法漏桶算法应用一个队列模仿一个漏水的桶。申请作为水滴进入队列,以恒定速率从队列中移除并解决。如果队列已满,新的申请将被回绝。 漏桶算法能够平滑申请流量,但它不能解决突发流量,因为申请解决速率是固定的。实现漏桶算法也绝对简单,因为须要在后盾应用定时器或其余机制来以恒定速率解决队列中的申请。 time/rate次要办法NewLimiter(limit Limit, burst int) *Limiter: 创立一个新的限流器,参数包含每秒容许的事件数量(limit)和令牌桶容量(burst)。(lim *Limiter) Allow() bool: 查看令牌桶中是否有可用的令牌。如果有可用令牌,则从桶中取走一个令牌并返回 true;否则返回 false。(lim *Limiter) AllowN(now time.Time, n int) bool: 与 Allow() 相似,但查看 n 个令牌是否可用。如果有足够的令牌,从桶中取走 n 个令牌并返回 true;否则返回 false。(lim *Limiter) Wait(ctx context.Context) error: 阻塞期待,直到有一个可用的令牌。如果在期待过程中 context 被勾销或超时,将返回一个谬误。(lim *Limiter) WaitN(ctx context.Context, n int) error: 阻塞期待,直到有 n 个可用的令牌。如果在期待过程中 context 被勾销或超时,将返回一个谬误。(lim *Limiter) Reserve() *Reservation: 返回一个预留令牌的 Reservation 对象。你能够依据须要期待预留令牌或勾销预留。(lim *Limiter) ReserveN(now time.Time, n int) *Reservation: 相似于 Reserve(),但预留 n 个令牌。各个办法的作用NewLimiter 用于创立一个新的限流器实例。Allow 和 AllowN 用于疾速查看是否有足够的令牌可用,这些办法非阻塞。Wait 和 WaitN 用于阻塞期待直到有足够的令牌可用,这些办法会阻塞。Reserve 和 ReserveN 用于预留令牌,容许您依据须要期待预留令牌或勾销预留。time/rate 是如何实现限流的time/rate 包基于令牌桶算法实现限流。限流器通过一个恒定速率(limit)向令牌桶增加令牌,直到桶的容量(burst)达到下限。每当解决一个申请时,限流器会尝试从令牌桶中取出一个或多个令牌。 ...

April 27, 2023 · 2 min · jiezi

关于go:极客时间Go实战训练营1期16周人生代代无穷已

download:极客工夫-Go实战训练营1期16周前后端拆散是一种在Web利用程序开发中宽泛采纳的架构模式。它的核心思想是将前端和后端齐全拆散,通过API接口进行通信。传统的Web开发中,前端和后端严密耦合,即前端和后端的代码在同一个我的项目中,前端次要负责页面展现,后端则负责数据处理和业务逻辑。然而,随着互联网技术的一直倒退,前后端拆散架构成为了越来越多Web应用程序的首选架构。 前后端拆散的长处: 进步零碎的可扩展性:在前后端拆散架构中,前端和后端是独立的两个零碎,能够分别独立开发、部署和保护。当须要减少新的性能时,只须要批改相应的API接口即可,不须要影响到整个零碎的运行。 减少了开发效率:因为前端和后端能够并行开发,大幅度缩短了开发周期,进步了开发效率。 反对多平台:因为前后端拆散,因而能够反对多个客户端平台,例如Web、挪动端等。 进步零碎的安全性:前后端拆散能够无效避免XSS攻打和CSRF攻打等对系统的平安威逼。 便于团队合作:前后端拆散能够让前端和后端的开发人员更加专一于本人的畛域,进步了团队合作效率。 前后端拆散的劣势: 须要更加简单的架构:相比传统的Web开发,前后端拆散须要更加简单的架构和技术栈,这也减少了开发成本和难度。 减少了开发工作量:在前后端拆散的架构中,前端和后端须要额定的开发工作量来实现API接口和数据交互等。 减少了部署难度和老本:因为前后端是两个独立的零碎,因而须要额定的配置和治理,这也减少了我的项目的部署难度和老本。 总之,前后端拆散是一种实用于大型Web应用程序的优良架构模式。它能够进步开发效率、加强零碎的可扩展性和安全性,并且反对多平台。然而,前后端拆散须要更加简单的架构和技术栈,并且须要额定的开发工作量和部署老本,因而须要依据具体情况进行抉择。

April 27, 2023 · 1 min · jiezi

关于go:Golang-WaitGroup-底层原理及源码详解

0 常识背景在进入注释前,先对 WaitGroup 及其相干背景常识做个简略的介绍,这里次要是 WaitGroup 的根本应用,以及零碎信号量的基础知识。对这些比拟相熟的小伙伴能够间接跳过这一节。 0.1 WaitGroupWaitGroup 是 Golang 中最常见的并发控制技术之一,它的作用咱们能够简略类比为其余语言中多线程并发管制中的 join(),实例代码如下: package mainimport ( "fmt" "sync" "time")func main() { fmt.Println("Main starts...") var wg sync.WaitGroup // 2 指的是上面有两个协程须要期待 wg.Add(2) go waitFunc(&wg, 3) go waitFunc(&wg, 1) // 阻塞期待 wg.Wait() fmt.Println("Main ends...")}func waitFunc(wg *sync.WaitGroup, num int) { // 函数完结时告知 WaitGroup 本人曾经完结 defer wg.Done() time.Sleep(time.Duration(num) * time.Second) fmt.Printf("Hello World from %v\n", num)}// 后果输入:Main starts...Hello World from 1Hello World from 3Main ends...如果这里没有 WaitGroup,主协程(main 函数)会间接跑到最初的 Main ends...,而没有两头两个 goroutine 的输入,加了 WaitGroup 后,main 就会在 wg.Wait() 处阻塞期待两个协程都完结后才继续执行。 ...

April 26, 2023 · 6 min · jiezi

关于go:go-websocket-使用

github => https://github.com/link1st/gowebsocket 文档: https://blog.csdn.net/m0_70556273/article/details/127306181 https://blog.csdn.net/u010750137/article/details/128439424 package mainimport ( "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "net/http")//设置websocket//CheckOrigin避免跨站点的申请伪造var upGrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true },}//websocket实现func ping(c *gin.Context) { //降级get申请为webSocket协定 ws, err := upGrader.Upgrade(c.Writer, c.Request, nil) if err != nil { return } defer ws.Close() //返回前敞开 for { //读取ws中的数据 mt, message, err := ws.ReadMessage() if err != nil { break } //写入ws数据 err = ws.WriteMessage(mt, message) if err != nil { break } }}func main() { r := gin.Default() r.GET("/ping", ping) r.Run(":12345")}应用melody三方库github: https://github.com/olahol/melody ...

April 26, 2023 · 1 min · jiezi

关于go:快速上手-Go-CGO掌握在-Go-里写-C

大家好,我是煎鱼。 最近因为各种奇怪的起因,接触到了 Go 特色之一 CGO。这方面的相干内容也绝对少一些,给大家抛砖引玉。 毕竟很多跨语言调用,还是会依赖 CGO 这个个性。心愿大家在真正要用时有个前置常识垫肚子。 CGO 是什么CGO 就是 C 和 Go,两个编程语言。指的是可能创立调用 C 代码的 Go 包。对照着 Go 代码中的 “C”: package mainimport "C"func main() {}一旦程序中呈现 import "C",则意味着开启 CGO 个性。在进行 go build 等阶段时,将会调用 C 编译器(通常是 gcc 或 clang)。 CGO 对应的环境变量是 CGO_ENABLED,设置为 1 则开启 CGO,为 0 则敞开 CGO。 编译命令如下: CGO_ENABLED=0 go build -o hellojy main.go当然,对于默认值。该环境变量值为 1,C 编译器也是应用 gcc。咱们能够通过 go env 看到: 一旦敞开就会影响 CGO 编译。须要特地注意,穿插编译时会默认敞开 CGO。 CGO 疾速上手最小 Demo先来一个 CGO 的 Go 例子: ...

April 26, 2023 · 2 min · jiezi

关于go:避坑Go并发编程时如何避免发生竞态条件和数据竞争

大家都晓得,Go是一种反对并发编程的编程语言,但并发编程也是比较复杂和容易出错的。比方本篇分享的问题:竞态条件和数据竞争的问题。会产生竞态条件和数据竞争的场景有哪些多个 goroutine 对同一变量进行读写操作。例如,多个 goroutine 同时对一个计数器变量进行减少操作。多个 goroutine 同时对同一数组、切片或映射进行读写操作。例如,多个 goroutine 同时对一个切片进行增加或删除元素的操作。多个 goroutine 同时对同一文件进行读写操作。例如,多个 goroutine 同时向同一个文件中写入数据。多个 goroutine 同时对同一网络连接进行读写操作。例如,多个 goroutine 同时向同一个 TCP 连贯中写入数据。多个 goroutine 同时对同一通道进行读写操作。例如,多个 goroutine 同时向同一个无缓冲通道中发送数据或接收数据。所以,咱们要明确的一点是:只有多个 goroutine 并发拜访了共享资源,就有可能呈现竞态条件和数据竞争。避坑方法当初,咱们曾经晓得了。在编写并发程序时,如果不审慎,没有思考分明共享资源的拜访形式和同步机制,那么就会产生竞态条件和数据竞争这些问题,那么如何防止踩坑?防止产生竞态条件和数据竞争的方法有哪些?请看上面: 互斥锁:应用 sync 包中的 Mutex 或者 RWMutex,通过对共享资源加锁来保障同一时间只有一个 goroutine 拜访。读写锁:应用 sync 包中的 RWMutex,通过读写锁的机制来容许多个 goroutine 同时读取共享资源,然而只容许一个 goroutine 写入共享资源。原子操作:应用 sync/atomic 包中提供的原子操作,能够对共享变量进行原子操作,从而保障不会呈现竞态条件和数据竞争。通道:应用 Go 语言中的通道机制,能够将数据通过通道传递,从而防止间接对共享资源的拜访。WaitGroup:应用 sync 包中的 WaitGroup,能够期待多个 goroutine 实现后再继续执行,从而保障多个 goroutine 之间的程序性。Context:应用 context 包中的 Context,能够传递上下文信息并管制多个 goroutine 的生命周期,从而避免出现因为某个 goroutine 阻塞导致整个程序阻塞的状况。实战场景互斥锁比方在一个Web服务器中,多个goroutine须要同时拜访同一个全局计数器的变量,达到记录网站访问量的目标。 在这种状况下,如果没有对拜访计数器的拜访进行同步和爱护,就会呈现竞态条件和数据竞争的问题。假如有两个goroutine A和B,它们同时读取计数器变量的值为N,而后都减少了1并把后果写回计数器,那么最终的计数器值只会减少1而不是2,这就是一个竞态条件。 为了解决这个问题,能够应用锁等机制来保障拜访计数器的同步和互斥。在Go中,能够应用互斥锁(sync.Mutex)来爱护共享资源。当一个goroutine须要访问共享资源时,它须要先获取锁,而后拜访资源并实现操作,最初开释锁。这样就能够保障每次只有一个goroutine可能访问共享资源,从而防止竞态条件和数据竞争问题。 看上面的代码: package mainimport ( "fmt" "sync")var count intvar mutex sync.Mutexfunc main() { var wg sync.WaitGroup // 启动10个goroutine并发减少计数器的值 for i := 0; i < 10; i++ {  wg.Add(1)  go func() {   // 获取锁   mutex.Lock()   // 拜访计数器并增加值   count++   // 开释锁   mutex.Unlock()   wg.Done()  }() } // 期待所有goroutine执行结束 wg.Wait() // 输入计数器的最终值 fmt.Println(count)}在下面的代码中,应用了互斥锁来爱护计数器变量的拜访。每个goroutine在拜访计数器变量之前先获取锁,而后进行计数器的减少操作,最初开释锁。这样就能够保障计数器变量的一致性和正确性,防止竞态条件和数据竞争问题。 具体的思路是,启动每个 goroutine 时调用 wg.Add(1) 来减少期待组的计数器。而后,在所有 goroutine 执行结束后,调用 wg.Wait() 来期待它们实现。最初,输入计数器的最终值。 ...

April 25, 2023 · 1 min · jiezi

关于go:Go免费学习资源整理

大家好,我是渔夫子。 邻近五一长假,在玩耍放松之际,也是一个给本人充电的好机会。上面是渔夫子给大家整顿的一些开源书籍和学习材料。心愿对你有所帮忙。 开源书籍《The Go Programming Languange》中文版,又名《Go语言圣经》 在线浏览地址:https://github.com/gopl-zh/gopl-zh.github.com 《Go语言高级编程》 在线浏览地址:https://github.com/chai2010/advanced-go-programming-book 《The Way To Go》中文版在线浏览地址: https://github.com/unknwon/the-way-to-go_ZH_CN 开源编程书籍合集在线浏览地址:https://github.com/EbookFoundation/free-programming-books/blob/main/books/free-programming-books-zh.md 在线浏览地址:https://github.com/justjavac/free-programming-books-zh_CN 技术面试必备基础知识、Leetcode、计算机操作系统、计算机网络、零碎设计在线浏览地址:https://github.com/CyC2018/CS-Notes 算法(Go语言版)在线浏览地址:https://github.com/0xAX/go-algorithms Go设计模式在线浏览地址: https://github.com/monochromegane/go_design_pattern PDF书籍文档链接: https://pan.baidu.com/s/1-erb1j57COWKTqOBzcspnA 提取码: qpxd 特地举荐:一个专一go我的项目实战、我的项目中踩坑教训及避坑指南、各种好玩的go工具的公众号,「Go学堂」,专一实用性,十分值得大家关注。关注送《100个go常见的谬误》pdf文档。

April 25, 2023 · 1 min · jiezi

关于go:有了-goimports为什么还需要-goimportx

goimportxgoimportx 能够帮忙开发者很好的治理 golang 的分组 个性主动对 go 导入进行排序和分组。反对自定义组规定。反对将后果写入文件。仅反对 go module。应用Go语言官网排序算法。只有一个 import 时主动删除括号。主动删除反复的空换行符。装置go install github.com/anqiansong/goimportx@latest应用goimportx --file /path/to/file.go帮忙命令goimportx --helpsort and group go importsUsage: goimportx [flags]Examples:goimportx --file /path/to/file.go --group "system,local,third"Flags: -f, --file string file path -g, --group string group rule, split by comma, only supports [system,local,third,others] (default "system,local,third") -h, --help help for goimportx -v, --version version for goimportx -w, --write write result to (source) file instead of stdout有了 goimports,为什么还须要 goimportx补救 goimports 只能按 零碎包,三方包 分组的有余,goimportx 反对依照 零碎包,本地包,三方包 分组补救 goimports 不能移出空行问题解决多个 import block 不能合并到一个 import block 问题

April 24, 2023 · 1 min · jiezi

关于go:Go-框架深入理解-gin-框中-Context-的-Request-和-Writer-对象

大家好,我是渔夫子。 明天跟大家聊一聊gin中Context对象中的Request和Writer对象。 背景在应用gin框架时,咱们定义的申请处理器,输出参数总是一个gin.Context的指针类型,代表申请的上下文。在处理器的业务逻辑中,通过Context.Request能够获取本次申请的参数值;通过Context.Writer就能将响应后果输入给客户端了。如下代码所示: package mainimport ( "github.com/gin-gonic/gin" "log" "net/http")func main() { r := gin.Default() // 注册路由,定义申请处理器函数 r.GET("/", func(c *gin.Context) { c.Param c.Writer.Write([]byte("Hello World")) }) // 调用该函数,则禁用日志带色彩输入 gin.DisableConsoleColor() //应用该函数,则强制日志带色彩输入,无论是在终端还是其余输出设备 gin.ForceConsoleColor() r.Run("127.0.0.1:8080")}那么,Context字段是在什么中央初始化的呢,为什么通过Context.Request字段就能读取申请的参数呢,又为什么通过Context.Writer字段就能将响应后果输入给客户端呢?接下来咱们就一一解答这3个问题。 Context对象的初始化gin的Context对象实际上是在Engine对象的ServeHTTP函数中进行初始化的,如下: // ServeHTTP conforms to the http.Handler interface.func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { c := engine.pool.Get().(*Context) c.writermem.reset(w) c.Request = req c.reset() engine.handleHTTPRequest(c) engine.pool.Put(c)}通过该函数咱们能够看到,在第3行通过池化技术获取到一个新的Context对象。获取到该Context后,通过engine.handleHTTPRequest函数传入Context参数,进而找到对应的路由处理器,传递给具体的路由处理器。在上例中就是r.GET中的对应处理器。 在这个函数中,还会把本次的申请体req赋值给Context.Request变量。这样,在具体的申请处理器中就能够通过Context的各种办法从Request中获取参数值了。比方GetHeader、GetRawData等。 咱们再来回顾下go的http的启动和申请解决流程,以便理解ServeHTTP的调用机会。engine对象实际上是实现了go的规范包中的Handler接口。该接口中定义了ServeHTTP办法。在接管到申请后,net/http的包就会调用engine的ServeHTTP办法。如下图中的engine.ServeHTTP局部: Context.Request对象在上节中,在Engine的ServeHTTP函数中,将函数的入参req赋值给了Context的Request对象。那么,这个req变量对象是从哪里来的呢? Engine.ServeHTTP函数是在net/http/server.go文件的conn.serve函数中被调用的。conn代表本次申请的连贯对象。conn.serve函数首先会从conn对象中读取出本次的申请参数(蕴含申请头等),并解析到request对象中,将该对象再赋值给Context中的Request字段。这样,通过Context的Param、Form、Header等函数,就能够从Request中读取信息了。 Context.Writer对象在具体的申请处理函数中,咱们发现所有的输入都是通过Context.Writer对象的Write函数将数据返回给客户端的。那么,这里的Context.Writer对象是什么呢,为什么通过Context.Writer就是能后果返回给客户端呢? 要答复这个问题,咱们还须要回到net/http/server.go文件的conn.serve函数中,response参数是在该函数中调用ServeHTTP时传入的参数,而该response参数是通过conn.readRequest函数返回的。 咱们再通过readRequest函数来看下response构造体的关键字段,如下: 咱们再来看Engine.ServeHTTP函数:首先,将response对象赋值给Context.writermem对象。即在c.writermem.reset(w)函数中执行的。其次,Context.Writer是对Context.writermem的援用。即Context.Writer仍然是指向response对象。即在c.reset()函数中执行的。 所以,在Context中跟response无关的关键字段如下: 最初,在业务逻辑中应用Context.Writer.Write函数输入时,实际上是执行的response.Write函数。 咱们再来看下response.Write函数的实现: 写入的时候是调用的response的w字段写入的。那w字段又是什么呢?咱们再回到server.go中的对response初始化的readRequest函数中,如下: ...

April 23, 2023 · 1 min · jiezi

关于go:为什么SyncPool不需要加锁却能保证线程安全

1. 简介咱们在 Sync.Pool: 进步go语言程序性能的要害一步 一文中,曾经理解了应用sync.Pool来实现对象的复用以缩小对象的频繁创立和销毁,以及应用sync.Pool的一些常见注意事项。 在这篇文章中,咱们将分析sync.Pool外部实现中,介绍了sync.Pool比拟奇妙的外部设计思路以及其实现形式。在这个过程中,也间接介绍了为何不加锁也可能实现线程平安。 次要会波及到Go语言中实现并发的GMP模型以及其根本的调度原理,以及本地缓存的设计,无锁队列的应用这几个局部的内容,综上这几个方面的内容实现了不加锁也可能保障线程平安。 2. GMP之间的绑定关系为了之可能帮忙咱们后续更好得了解sync.Pool的设计与实现,这里须要对GMP模型进行简略的介绍。GMP模型是Go语言中的一种合作式调度模型,其中G示意Goroutine,M能够了解为内核线程,P为逻辑处理器,简略了解其保护了一条Goroutine队列。 2.1 M和P的关系在GMP模型中,M和P能够动静绑定,一个M能够在运行时绑定到任意一个P上,而一个P也能够与任意一个M绑定。这种绑定形式是动静的,能够依据理论状况进行灵便调整,从而实现更加高效的协程调度。 只管M和P能够动静绑定,但在特定工夫点,一个M只会对应一个P。这是因为M是操作系统线程,而P是Go语言的逻辑处理器,Go语言的逻辑处理器须要在某个操作系统线程中运行,并且是被该逻辑处理器(P)独自占用的。 P的数量个别是和CPU核数保持一致,每个P占用一个CPU外围来执行,能够通过runtime.GOMAXPROCS函数来批改。不过在大多数状况下,不须要手动批改,Go语言的调度器会依据理论状况主动进行调整。 2.2 P和G的关系刚创立的Goroutine会被放入以后线程对应P的本地队列中期待被执行。如果本地队列已满,则会放入全局队列中,供其余线程的P来抢占执行。 当P闲暇时,会尝试从全局队列中获取Goroutine来执行。如果全局队列中没有Goroutine,则会从其余处理器的本地运行队列中"偷取"一些Goroutine来执行。 如果协程执行过程中遇到阻塞操作(比方期待I/O或者锁),处理器(P)会立刻将协程移出本地运行队列,并执行其余协程,直到被阻塞的协程能够继续执行为止。被阻塞的协程会被放到相应的期待队列中期待事件产生后再次被唤醒并退出到运行队列中,但不肯定还是放回原来的处理器(P)的期待队列中。 从上述过程能够看出,G和P的绑定关系是动静绑定的,在不同的工夫点,同一个G可能在不同的P上执行,同时,在不同的工夫点,P也会调度执行不同的G。 2.3 总结每个P在某个时刻只能绑定一个M,而每个G在某个时刻也只存在于某个P的期待队列中,期待被调度执行。这是GMP模型的根本调度原理,也是Go语言高效调度的外围所在。通过动静绑定和灵便调度,能够充分利用多核处理器的计算能力,从而实现高并发、高效率的协程调度。 通过对GMP模型的根本理解,可能帮忙咱们后续更好得了解sync.Pool的设计与实现。 3.Sync.Pool与GMP模型3.1 sync.Pool性能问题这里咱们回到sync.Pool, 能够简略应用切片,存储可复用的对象,在须要时从中取出对象,用完之后再从新放回池子中,实现对象的重复使用。 当多个协程同时从 sync.Pool 中取对象时,会存在并发问题,因而须要实现并发平安。一种简略的实现形式是加锁,每个协程在取数据前先加锁,而后获取数据,再解锁,实现串行读取的成果。然而这种形式在并发比拟大的场景下容易导致大量协程进入阻塞状态,从而进一步升高性能。 因而,为了进步程序的性能,咱们须要寻找一种缩小并发抵触的形式。有什么形式可能缩小并发抵触呢? 3.2 基于GMP模型的改良回到GMP模型,从第二节对GMP模型的介绍中,咱们晓得协程(G)须要在逻辑处理器(P)上执行,而逻辑处理器的数量是无限的,个别与CPU外围数雷同。而之前的sync.Pool实现形式是所有P竞争同一份数据,容易导致大量协程进入阻塞状态,影响程序性能。 那咱们这里,是不是可能将 sync.Pool 分成多个小的存储池,每个P都用领有一个小的存储池呢? 在每个小存储池中别离应用独立的锁进行并发管制。这样能够防止多个协程同时竞争同一个全局锁的状况,升高锁的粒度,从而缩小并发抵触。 协程运行时都须要绑定一个逻辑处理器(P),此时每个P都有本人的数据缓存,须要对象时从绑定的P的缓存中获取,用完后从新放回。这种实现形式缩小了协程竞争同一份数据的状况,只有在同一个逻辑处理器上的协程才存在竞争,从而缩小并发抵触,晋升性能。 3.3 能不能齐全不加锁在下面的实现中,处于不同的P上的协程都是操作不同的数据,此时并不会呈现并发问题。惟一可能呈现并发问题的中央,为协程在获取缓存对象时,逻辑处理器中途调度其余协程来执行,此时才可能导致的并发问题。那这里能不能防止并发呢? 那如果可能将协程固定到逻辑处理器P上,并且不容许被抢占,也就是该P上永远都是执行某一个协程,直到胜利获取缓存对象后,才容许逻辑处理器去调度执行其余协程,那么就能够完全避免并发抵触的问题了。 因而,如果咱们可能做到协程在读取缓冲池中的数据时,可能齐全占用逻辑处理器P,不会被抢占,此时就不会呈现并发了,也不须要加锁了。 侥幸的是,runtime包中提供了runtime_procPin调用,能够将以后协程固定到协程所在逻辑处理器P上,并且不容许被抢占,也就是逻辑处理器P始终都被以后协程所独享。在获取缓存对象时,咱们能够应用runtime_procPin将以后协程固定到逻辑处理器P上,而后从该逻辑处理器P的缓存中获取对象。这样做不仅能够防止并发抵触,还能够防止上下文切换和锁竞争等性能问题。 4. sync.Pool初步实现上面来看看以后sync.Pool的局部代码,其原理便是上述所提到的形式。具体来说,每个逻辑处理器P保留一份数据,并利用runtime_procPin来防止同一逻辑处理器P中的协程产生并发抵触。 须要留神的是,上面所展现的代码只是局部代码,并不蕴含残缺的实现。然而这些代码涵盖了后面所提到的实现形式。同时,为了讲述不便,也批改局部实现,后文会阐明以后sync.Pool以后真正的实现。 4.1 sync.Pool构造体定义type Pool struct { // 指向 poolLocal 构造体切片的地址,长度与cpu外围数保持一致 local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal // 记录以后 poolLocal 切片的长度 localSize uintptr // size of the local array // New optionally specifies a function to generate // a value when Get would otherwise return nil. // It may not be changed concurrently with calls to Get. New func() any}type poolLocal struct { // 上文所说的小缓冲池的实现 private []any // Can be used only by the respective P.}其中,New 函数用于创立一个新的对象,以便向池中增加对象。当池中没有可用对象时,会调用该函数。local 是指向 poolLocal 切片的指针,poolLocal 即为上文提到的小缓冲池,每个逻辑处理器都有一个。 ...

April 22, 2023 · 4 min · jiezi

关于go:使用-Wails结合-Go-和-Web-技术轻松构建桌面应用程序

Wails 是一个我的项目,能够让您应用 Go 和 Web 技术编写桌面应用程序。它能够被视为 Go 的疾速、轻量级的 Electron 替代品。联合丰盛的古代前端,您能够应用 Go 的灵活性和弱小性能,轻松构建应用程序。 在之前发的AsBot客户端 中xiaoz正是应用Wails技术来进行开发。 Wails性能原生菜单、对话框、主题和半透明Windows、macOS 和 linux 反对内置 Svelte、React 、Preact 、Vue、Lit 和 Vanilla JS 的模板从 JavaScript 轻松调用 Go 办法主动将 Go 构造体转换为 TypeScript 模块Windows 上不须要 CGO 或内部 DLL应用 Vite 的实时开发模式能够轻松创立、构建和打包利用的弱小命令行工具丰盛的 运行时库应用 Wails 构建的应用程序兼容 Apple & Microsoft 商店什么状况下适宜抉择Wails提起跨平台客户端开发,就会想到Electron。Electron是跨平台客户端开发的首选,许多出名软件,如VScode和腾讯QQ的重构版,都是应用Electron开发的。然而,Electron也存在一些毛病,例如内存占用量高、应用程序体积大且须要相熟Node.js。如果您无奈容忍这些毛病,同时满足以下条件,您能够思考应用Wails。 适宜状况: 开发一些简略的客户端您曾经相熟Golang这门开发语言您曾经相熟一门Web 前端框架,比方Vue3如果您曾经把握了上述要求,那么齐全能够应用Wails来开发跨平台客户端。但如果您不相熟上述技术栈,我不倡议抉择Wails,因为学习老本可能比Electron更高。 Wails疾速上手xiaoz在应用Wails开发的时候,搭配的前端技术是Vue3,但Wails不仅仅是反对Vue3,包含Svelte、React等都是能够的。 环境要求: Go 1.18+NPM (Node 15+)装置Wails的话参考帮忙文档就行了:Wails装置 开始开发 Wails我的项目创立胜利后,你就能够在frontend目录下进行前端工作的开发了。如果应用Vue3作为前端技术的话,通常还须要搭配Vue Router、Pinia、axios等JavaScript 库一起应用。 而后再选一个你相熟的Vue 3 UI组件库,比方Element Plus啥的。 参数选项 如果您须要对应用程序参数做出批改,能够在main.go这外面进行设置,比方默认窗口大小、题目等,具体能够参考官网文档:应用程序参数 前端与后端通信 如果你在前端中想要调用Golang提供的后端办法,能够在app.go中编写本人的办法。比方: // 扫描文件并入库func (a *App) ScanFiles(path string) string { result := controller.Scan(path) return result}如果前端须要调用ScanFiles()这个办法,须要先导入: ...

April 20, 2023 · 1 min · jiezi

关于go:Kubernetes系统精讲-Go语言实战K8S集群可视化无密

Kubernetes零碎精讲 Go语言实战K8S集群可视化download:https://www.666xit.com/3948/Kubernetes(K8S)是一个开源的容器编排零碎,它能够主动部署、扩大和治理容器化应用程序。Go语言是一种简略、高效、并发的编程语言,它在Kubernetes的开发中被宽泛应用。本文将介绍如何应用Go语言编写Kubernetes控制器。 Kubernetes控制器是一种用于治理资源的自定义控制器。Kubernetes通过API对象来示意和治理集群中的各种资源,例如Pod、Service、Deployment等。控制器能够监督这些资源的状态,并依据须要采取操作,以确保它们处于所需的状态。 要编写Kubernetes控制器,咱们须要应用客户端-go库,该库提供了许多用于与Kubernetes API交互的工具。应用此库,咱们能够轻松地获取无关以后部署的信息,并且能够执行必要的操作来保护所需的状态。 以下是一个简略的示例控制器,该控制器监督名为“example”命名空间中的所有Pod,并在其中增加或删除标签。 package mainimport ( "context" "fmt" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd")func main() { config, err := clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig") if err != nil { panic(err.Error()) } clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err.Error()) } for { pods, err := clientset.CoreV1().Pods("example").List(context.TODO(), metav1.ListOptions{}) if err != nil { panic(err.Error()) } fmt.Printf("There are %d pods in the cluster\n", len(pods.Items)) for _, pod := range pods.Items { fmt.Printf("Pod %s has labels: %v\n", pod.Name, pod.Labels) // Add or remove label labels := pod.Labels labels["mylabel"] = "foo" pod.Labels = labels _, err := clientset.CoreV1().Pods("example").Update(context.TODO(), &pod, metav1.UpdateOptions{}) if err != nil { panic(err.Error()) } } time.Sleep(time.Second * 10) }}在此示例中,咱们首先应用客户端-go库设置与Kubernetes API的连贯。而后,咱们应用循环定期地获取名为“example”命名空间中的所有Pod,并将标签增加到它们上。 ...

April 20, 2023 · 1 min · jiezi

关于go:Go框架gin中日志文字的颜色是如何实现的

大家好,我是渔夫子。 当咱们在终端上(比方Goland)运行gin框架搭建的服务时,会发现输入的日志是能够带色彩的。比方下图中的最初一行,就是申请一个办法时的输入日志: 咱们看到状态码200和申请的办法GET都带有不同色彩的背景。那么,这种带色彩的日志是如何实现的呢? 一、gin中管制日志色彩首先,在gin框架中提供了管制日志文字是否带色彩输入的办法:DisableConsoleColor和ForceConsoleColor。调用办法如下: package mainimport ( "github.com/gin-gonic/gin" "log" "net/http")func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { names := []string{"Hello", "World", ""} c.SecureJSON(http.StatusOK, names) }) // 调用该函数,则禁用日志带色彩输入 gin.DisableConsoleColor() //应用该函数,则强制日志带色彩输入,无论是在终端还是其余输出设备 gin.ForceConsoleColor() r.Run("127.0.0.1:8080")}这里要留神的就是,如果这两个函数都不调用,那么默认是在终端中输入日志是带色彩的,输入到其余中央是不带色彩的。 如下,咱们将gin的日志输入到文件中,并别离查看应用gin.ForceConsoleColor函数和不应用gin.ForceConsoleColor的日志区别。 那么,当咱们应用tail -n 10 log2.out,在终端上显示该文件的内容时,第一行就会按色彩显示,第二行就没有色彩。如下: 二、终端输入文字色彩是如何实现的?其实现原理实际上是利用了ANSI的换码符。所谓换码符就是一套编码规定,用于管制终端上的光标地位、色彩和其余选项。 在ascii码表中,换码符的字符标识是:ESC (escape),其对应的8进制、10进制和16进制以及unicode码别离如下: Octal: \033Decimal: 27Hexadecimal: \x1BUnicode: \u001b在linux终端中,色彩的管制应用“\033[”结尾,以"m"结尾的形式设置特定的色彩。比方在gin框架中对色彩常量的定义如下: const ( green = "\033[97;42m" white = "\033[90;47m" yellow = "\033[90;43m" red = "\033[97;41m" blue = "\033[97;44m" magenta = "\033[97;45m" cyan = "\033[97;46m" reset = "\033[0m")其中 ";"字符前后的数字别离示意字体的背景色和前景色(字体色彩)。 ...

April 20, 2023 · 1 min · jiezi

关于go:golang-实现-ldif-数据转成-json-初探

theme: Chinese-red「这是我参加11月更文挑战的第 8 天,流动详情查看:2021最初一次更文挑战」上一篇咱们分享了如何将 ldif 格局的数据,转换成 json 数据的思路并画相应的简图 这一次,咱们就来实现一下 实现形式如下: 连贯服务器,查问 ldap 服务器上数据结构 ,goalng 如何获取 ldap 服务器的数据? 有说到遍历每一条 entry解决每一条 entry 的时候,从右到左获取相应的 rdn(对应的键和值),并给每一个 rdn 创立一个 多叉树的 节点basedn 对应的节点 和 每一个 ou 对应的节点地址,寄存到一个 map(key 是 string,value 是节点的地址) 中便于后续遍历解决其余 entry 的时候,间接通过 ou 名字获取对应节点地址即可对于一个节点上面的用户,间接挂到这个节点上即可来一起看看数据结构和 main 函数 数据结构为节点的必要信息 // 节点信息type lNode struct { Name string Path string Children []*lNode User []string}// 新建一个节点func NewNode(name, path string) *lNode { return &lNode{ Name: name, Path: path, Children: []*lNode{}, User: []string{}, }}main 函数的执行流程具体如下: ...

April 19, 2023 · 2 min · jiezi

关于go:Go-的一些有趣数据中国最多人用开发者年轻PHP-明显下滑的趋势

大家好,我是煎鱼。 最近看到 JetBrains 家的《 2021~2022 开发者生态系统现状》,Go 有些数据还挺乏味的,分享给大家。这样能够对整体的开发者生态有肯定的理解。 以后的趋势 我总结和梳理了十条,如下: 用 Go 最多的 TOP3:中国、日本、俄罗斯联邦。用 Go 开发的软件类型 TOP5:网站、实用工具、IT 基础架构、系统软件、库/框架。Go 的编程群体比拟年老:21-29 岁占了 50%,30-39 岁占了 31%。18-20 占了 5%。Go 在新语言中较受欢迎:如果选用新编程语言,大家会抉择 Go 或 Rust 的人更多一些。Go 次要被用于的畛域 TOP3:Web(后端)、服务器/根底软件、云。Go 在世界上的应用状况:2021~2022 年间,小幅回升(17% 到 19%)。最受欢迎和最不受欢迎的语言:JavaScript 和 Java 均名落孙山。最受欢迎的五种编程语言:Python、Java、JavaScript、C# 和 Kotlin。在应用趋势上呈降落趋势的有:PHP、Ruby、Objective-C 和 Scala 。世界上应用最宽泛的编程语言 TOP3:JavaScript、Python、Java。乏味的景象 比拟乏味的几个景象: 日本应用 Go 是第二多的?莫非都是咱们跑去写的吗。挺神奇的。Go 在大学生中的应用比例上临时不太多,18-20 岁只有 5%,这块官网次要调研的就是大学生群体。自 2020 年起,Java 的应用人群比例有所下滑,感觉是天花板到顶了,转平滑稳定增长了。总结世界上最好的语言 PHP 有显著降落的趋势,如果你还年老。倡议尽快上手第二门编程语言。 整体上 Go 的很多景象咱们这会被放大。因为咱们是目前世界上应用 Go 最大的群体,Go 绝对 PHP 的后劲是更大的。 在榜三的 Java 和 JavaScript,过来了那么多年。仍然是一门让人又爱又 ”恨“ 的编程语言。应用人群之多,问题也不少。 ...

April 19, 2023 · 1 min · jiezi

关于go:Go指针未初始化越界悬挂问题以及优点

对于指针未初始化、指针越界、指针悬挂指针未初始化可能会导致程序解体或者呈现奇怪的行为,看看上面这个例子:<!----> package mainimport "fmt"type MyStruct struct { value string}func (s *MyStruct) SetValue(val string) { s.value = val}func (s *MyStruct) GetValue() string { return s.value}func main() { var myStruct *MyStruct myStruct.SetValue("hello") fmt.Println(myStruct.GetValue())}申明了一个指向MyStruct的指针myStruct,然而没有为它分配内存,也就是说它的值为nil。通过myStruct指针来设置构造体的值和获取构造体的值。因为myStruct指针没有初始化,它不会指向任何无效的内存地址,在SetValue和GetValue办法中会呈现谬误。 革新main函数即可 func main() { myStruct := &MyStruct{} myStruct.SetValue("tantianran") fmt.Println(myStruct.GetValue())}应用\&MyStruct{}创立了一个新的构造体对象,并将其地址调配给指针myStruct。这样,指针就指向了一个无效的内存地址。 指针越界可能会导致程序解体或者呈现奇怪的行为,看上面的案例:<!----> package mainimport "fmt"func main() { mySlice := []int{1, 2, 3, 4, 5} myPointer := &mySlice[2] fmt.Println(*myPointer) *myPointer = 6 fmt.Println(mySlice) myPointer = &mySlice[len(mySlice)] // 超出数组范畴 *myPointer = 7 fmt.Println(mySlice)}创立了一个名为mySlice的整数切片,并且创立了一个指向切片中第三个元素的指针myPointer。而后通过指针myPointer来批改切片中的第三个元素,并且打印了批改后的切片。接着试图将指针myPointer指向超出切片范畴的地位,即最初一个元素的下一个地位,而后再通过指针来批改该地位的值。这就是指针越界了,所以程序会解体并且抛出一个运行时谬误。 当初修复这个问题,确保指针不越界: package mainimport "fmt"func main() { mySlice := []int{1, 2, 3, 4, 5} myPointer := &mySlice[2] fmt.Println(*myPointer) *myPointer = 6 fmt.Println(mySlice) if len(mySlice) > 0 {  myPointer = &mySlice[len(mySlice)-1]  *myPointer = 7  fmt.Println(mySlice) }}下面的代码中,我退出了一个判断语句,查看切片是否为空。如果切片不为空,就将指针指向最初一个元素,并且通过指针来批改该地位的值。这样指针就不会越界了,程序就能够失常运行啦! 指针悬挂是指一个指针指向曾经开释的内存或者未被调配的内存区域,看上面的案例:<!----> package mainfunc foo(pp *int) { var x int = 10 pp = &x // pp指向x的地址,然而在函数返回时,pp指向的地址被开释了,变成了悬挂指针}func main() { var p *int foo(p) *p = 10 // p是一个悬挂指针,此处会导致运行时谬误} 要修复指针悬挂问题,能够将foo函数批改为返回指向x的指针。这样,在main函数中,就能够应用这个指针来拜访x变量,而不会呈现悬挂指针的状况。上面是批改后的代码: package mainimport "fmt"func foo() *int { var x int = 10 return &x // 返回指向x的指针}func main() { var p *int p = foo() fmt.Println(*p) // 批改前 *p = 100        // 此时p指向x的地址,能够平安地批改x的值 fmt.Println(*p) // 批改后}应用指针的长处案例假如有一个十分大的数据结构,它须要在程序中频繁地传递和操作。如果应用值传递来操作该数据结构,每次传递都会创立该数据结构的正本,这将节约大量的工夫和内存资源。应用指针传递该数据结构,只需传递指向该数据结构的内存地址,而不是复制整个数据结构。大大减少内存应用和程序运行工夫:<!----> package mainimport "fmt"type LargeData struct { // 一个十分大的数据结构 data [1024 * 1024 * 1024]int}func processLargeData(dt *LargeData) { // 对大型数据结构进行解决 dt.data[0] = 1 // ...}func main() { // 创立一个大型数据结构 data := LargeData{} // 传递指向该数据结构的指针进行解决 processLargeData(&data) fmt.Println(data.data[0]) // 输入 1}比方正在解决一个HTTP申请,并且须要从申请中读取和解析JSON数据,而后将其转换为一个Go构造体并进行解决。能够通过将申请体指针传递给解析函数来防止大量的内存拷贝,防止创立一个新的缓冲区将申请体数据复制到缓冲区中进行解析:<!----> import (    "encoding/json"    "net/http")type Person struct {    Name string `json:"name"`    Age  int    `json:"age"`}func handler(w http.ResponseWriter, r *http.Request) {    decoder := json.NewDecoder(r.Body)    defer r.Body.Close()    var person Person    if err := decoder.Decode(&person); err != nil {        http.Error(w, "Invalid request body", http.StatusBadRequest)        return    }    // 解决person构造体    // ...    w.WriteHeader(http.StatusOK)}Decode()函数的参数是\&person,它将指向Person构造体的指针传递给解析函数。解析函数能够间接在申请体上工作,而不须要进行内存拷贝,从而进步了程序的性能。 打个比方,正在编写一个HTTP服务器,该服务器须要解决大量的申请并保护一个长时间运行的状态,能够应用指针来动静地调配和开释内存来存储和治理状态数据:<!----> package mainimport ( "fmt" "log" "net/http")type ServerState struct { Count int}func main() { state := &ServerState{} // 用浏览器拜访,每刷新一次就会累加 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {  state.Count++  fmt.Fprintf(w, "计数: %d", state.Count) }) log.Fatal(http.ListenAndServe(":8080", nil)) // 在服务器敞开时开释状态内存 defer func() {  fmt.Println("web服务器敞开...")  // 开释ServerState构造体内存  if state != nil {   state = nil  } }()}拜访成果: 下面的代码中,应用\&ServerState{}来动静地分配内存来存储服务器状态。在解决申请时,应用指针state来更新和拜访状态数据。在服务器敞开时,应用指针state来开释状态内存。这就不便地管理程序的内存,也防止了内存透露和资源节约的问题。所以说,应用指针来动态分配和开释内存,这在解决大量数据或长时间运行的服务时就显得尤为重要啦。 本文转载于WX公众号:不背锅运维(喜爱的盆友关注咱们):https://mp.weixin.qq.com/s/_EVBga-jn5Sg94p-Aq0D-w

April 19, 2023 · 1 min · jiezi

关于go:何必去卷-AI对于普通人简单好用的智能软件

一天,小明要写一篇论文,然而他遇到了一个问题:他冀望有这么一个软件能够智能精准回复,能进行训练,还能帮忙解决数据。于是他开始寻找解决方案。 能够应用最近很火很卷的 chatgpt 呀,于是简略搜寻并理解了一下 什么是 chatgpt 什么是 chatgpt Chatgpt 是一种基于自然语言解决技术的智能聊天零碎。它能够主动了解用户输出的文本,并作出相应的回应,从而与用户进行实时的对话。 Chatgpt 通常应用机器学习和深度学习算法来训练它的模型,以便更好地了解和响应用户的输出。它还具备自我学习和适应性能力,因而能够依据与用户的交互不断改进和优化其性能。 Chatgpt 曾经被广泛应用于各个领域,例如客服、营销、教育等。它能够无效地进步服务质量、节省时间老本,并进步用户满意度。 ChatGPT 于 2022 年 11 月推出,只管其答复事实的准确性受到批评,但因其具体和清晰的回复而受到关注。 再持续搜寻,看到网上的注册和应用教程铺天盖地,本人看的目迷五色,小明随机选了一个教程进行学习和尝试,然而跟着教程来发现自己须要达到教程上的成果差距还很显著 例如须要不一样的网络,须要购买 openai 的账号,为了可能更好的服务小明,还要思考去买更加智能的 chatgpt 4 折腾了一圈,发现自己工夫,精力耗费了不少,花了不少钱,然而并没有达到本人冀望的后果,那就是冀望有软件来帮忙本人,解决本人的一些问题,数据处理,材料查找等。 其实咱们身边有很多这样的敌人,花了钱,花了精力,本人没有折腾出个所以然,实际上本人的需要其实很简略,就是可能不便的用上 chatgpt 的能力,本人还不必管软件的部署环境,软件的账号是否能够应用的问题 并且咱们身边的敌人还遇到了这样的问题,买了账号之后,发现自己应用不标准,本人的账号被封了,没有方法应用调用 api 的形式来享受 chatgpt 的能力 那么是否能够有这样一个软件就像手机外面的 app,或者小程序一样呢?间接在海外的环境中就能够间接简略便捷的去寻找咱们冀望的答案,如同身边有一个小助手一样,帮咱们解决数据,答复咱们的问题 对于程序员,能够问他对于编程方面的书籍举荐,进阶路线,理论问题解决方案,代码编写,甚至是代码纠错也是十分 nice 的 对于白领,能够问他对于工夫治理,材料整顿,人际交往,个人成长 等等问题,他也能像人一样给予你很好的领导 对于学生,你能够问他对于学科材料,解题计划,具体的论点数据等,不必上到某些搜索引擎上搜寻半天还看了一堆的广告好太多了 ![]() 对于宝妈, 天然也是齐全 ok 的,你能够理解对于育儿的技巧,对于如何解决好亲密关系,如何疏导孩子健康成长 只有你有向外的需要,你就能够应用这个软件,为你晋升效率,晋升品质,节俭进去的工夫,你能去做更多有价值有意义的事件 那么他是谁呢? 他就是 南羽云 Ai 助手 南羽云Ai助手 应用 南羽云 Ai 助手 你能够无需思考本人部署环境,购买 openai 账号,甚至都不须要去关怀你的网络是否非凡的问题 首先,它的举荐十分精确,让你省去了大量的工夫和精力去搜寻和比拟各种软件; 其次,它还提供了各种实用的性能和工具,让你的钻研更加高效和便捷。 ...

April 18, 2023 · 1 min · jiezi

关于go:数据结构和算法之二叉树篇

文章目录1.什么是二叉树?2.二叉树如何遍历?3.二叉树如何应用?前言:自己理论开发中用到的二叉树的场景很少,但为啥还是要学习二叉树呢?答:自己开发教训只有几年工夫,教训不是很丰盛,没怎么在理论场景用过二叉树的开发,更多的是在刷leecode时,会频繁遇到二叉树的题目。但我晓得,随着一直的深刻学习,当前接触到一些底层原理时,必定离不开数据结构和算法,学习二叉树也是为了当前本人能迈向更高的台阶做铺垫。这里我用go语言作为例子解说(目前我只把握了php和go,php实现没那么不便,所以用go),其余语言的的实现也相似,只是根本的数据相似不同而已。 PS:有时候也能刚好用数据结构和算法去更好的了解一些货色.比方php的sort函数的排序,点进去看其实底层的c代码是通过疾速排序和插入排序相互联合,去给传入的数组进行排序的。当数组元素超过16个时应用疾速排序(工夫复杂度是n*logN的排序),小于等于16个时应用插入排序(工夫复杂度是n2的排序),去实现最快的效率进行排序。还有mysql的索引是多路均衡树结构实现的,对树结构有基本概念,了解mysql索引时也能更加深刻。 好了废话少说间接进入正题。 1.什么是二叉树?二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简略且最重要的树。间接上图就好了解了 就相似上图构造的一种数据后果,就是二叉树,用代码实现就是二叉树节点构造 //定义二叉树节点type Node struct { data int //data构造体的字段名 类型是int 能够这样拜访Node.data = 2 left *Node // left构造体的字段名 类型是Node指针 right *Node // right构造体的字段名 类型是Node指针}例子: package mainfunc main() { //初始化 node1 := Node{1, nil, nil} node2 := Node{2, nil, nil} node3 := Node{3, nil, nil} node1.left = &node2 node1.right = &node3 //node1就是根结点,节点值是1,node2就是左结点,节点值是2,node3就是右结点,节点值是3, }2.二叉树如何遍历?有先序遍历(先遍历头节点,再遍历左节点,再遍历右节点,艰深来说程序就是:头左右),中序遍历(程序:左头右),后序遍历(程序:左右头). 举例下图这么一颗二叉树则程序为 代码实现为: package mainimport "fmt"func main() { //初始化 node1 := Node{1, nil,nil} node2 := Node{2, nil,nil} node3 := Node{3, nil,nil} node4 := Node{4, nil,nil} node5 := Node{5, nil,nil} node6 := Node{6, nil,nil} node7 := Node{7, nil,nil} node1.left = &node2 node1.right = &node3 node2.left = &node4 node2.right = &node5 node3.left = &node6 node3.right = &node7 Order(&node1)}//定义二叉树节点type Node struct { data int left *Node right *Node}//递归形式func Order(head *Node) { if head == nil { return } //fmt.Println(head.data) 先序遍历 1245367 Order(head.left) //fmt.Println(head.data) //中序遍历 4251637 Order(head.right) fmt.Println(head.data) //后序遍历 4526731}3.二叉树有什么类型呢?有4种类型1.搜寻二叉树2.齐全二叉树3.满二叉树4.均衡二叉树 ...

April 18, 2023 · 1 min · jiezi

关于go:ldap-组织结构如何转成多叉树

工作中,ldap 服务器的对接,能够能会波及到同步组织构造,认证,认证后处理等等,最近认证还不是我想写的刚需,持续来看看对于组织构造的想法 例如同步 AD 域的组织构造,或者是 ldap 协定的其余产品对应的企业组织构造,如下我简略的创立的一些 ou 和 cn 查看以后 ldap 组织构造咱们通过命令查看 ldap 服务器上的组织构造数据,咱们只查看 DN 即可,不须要其余的属性 # ldapsearch -x -LLL -b dc=xiaomotong,dc=com objectClass=* d: 咱们能够看到,ldap 服务器给咱们返回的数据中,是 1 个 list ,这个list 外面每 1 个元素是 1 个 entry,是 1 条记录,也是 1 个惟一的标识 那么问题就很明确了,如何将上述的 dn list ,转成 1 棵树呢? 咱们能够根据上述打印后果画图,进行剖析一下 先画一棵树依据下面的打印后果,在和理论ldap admin 可视化工具中能够看出,根理论是在最初 dc=xiaomotong,dc=com,而后从右往左 别离是 ou,cn 前 5 条数据对应画进去的图是这样的: 看上去有戏,持续往下画看看成果: 红色框为 ou绿色框为 dc蓝色框为 cn 对就是这样的一棵树,画进去了,可是咱们如何用代码实现一下呢? 编码实现编码实现将 ldif 格局的数据转成树,并用 json 的形式输入,查看成果 ...

April 17, 2023 · 1 min · jiezi

关于go:go基于范型的-gin-开发脚手架

GingoIntroduceGingo是基于 gin 框架为外围的脚手架,可能疾速创立Restful格调的API接口,并且能提供简略的后盾治理性能,应用本我的项目能够疾速实现业务逻辑开发。 Github: https://github.com/songcser/gingo Featuregin框架,简略,高效,轻量gorm数据库ORM框架,封装mapper,应用简略viper配置管理zap日志框架,输入日志更灵便api接口封装,疾速实现CURD操作,提供Restful格调接口admin后盾治理,实现了简略的后盾治理,不便进行数据管理应用范型,go版本不能低于1.18Catalogue.|——.gitignore|——go.mod|——go.sum|——cmd └──migrate └──main.go // 注册数据库表 └──main.go // 我的项目入口main|——README.md|——config // 配置文件目录| └──autoload // 配置文件的构造体定义包| └──admin.go // admin配置| └──db.go| └──jwt.go // jwt配置| └──mysql.go // mysql配置| └──zap.go // zap日志配置| └──config.yaml // .yaml配置示例文件| └──config.go // 配置初始化文件|——initialize // 数据初始化目录| └──admin.go // admin初始化| └──constants.go // 常量数据| └──gorm.go // 数据库初始化| └──mysql.go // mysql初始化| └──router.go // gin初始化| └──swagger.go | └──viper.go // viper配置初始化| └──zap.go // zap日志初始化|——internal // 该服务所有不对外裸露的代码,通常的业务逻辑都在这上面,应用internal防止谬误援用|──middleware // 中间件目录| └──logger.go // 日志中间件,打印申请数据| └──recovery.go // 自定义recovery, 输入谬误格式化|──pkg // 外部服务包 | └──admin // admin实现逻辑| └──admin.go| └──init.go| └──model.go| └──service.go| └──api // API接口封装| └──api.go| └──auth // 登陆受权接口封装| └──model.go | └──user.go | └──model // 底层模型封装| └──mapper.go | └──model.go | └──page.go | └──wrapper.go | └──response // 响应数据模型封装| └──page.go | └──response.go | └──router // 路由模块封装| └──router.go | └──service // 服务模块封装| └──service.go|──templates // admin模版页面| └──add.html // 新建页面| └──edit.html // 编辑页面| └──embed.go | └──header.html // 头部页面| └──home.html // 首页| └──index.html // 主页面| └──login.html // 登陆页面| └──register.html // 注册页面页面| └──sidebar.html // 右边栏页面|──utils // 一些工具办法| └──cache.go // 缓存| └──error.go // error查看| └──hash.go // hash加密解密| └──http.go // http客户端申请| └──json.go // | └──jwt.go // JWT| └──path.go // 文件门路| └──time.go // time相干办法| └──translator.go // 中英文翻译Usageinternal目录是不对外裸露的代码,在做go get时,此目录不会被下载,所以通常业务逻辑放在这个上面。咱们将在这个目录上面加一些业务代码,阐明脚手架的应用。 ...

April 17, 2023 · 4 min · jiezi

关于go:Wails在MacOS下无法使用cookies的BUG解决方案

Wails 是一个能够让您应用 Go 和 Web 技术编写桌面利用的我的项目。最近在 MacOS 下开发 AsBot客户端 时,开发模式一切正常,但编译打包后发现 cookies 无奈应用。 在此之前我曾经将 Windows 客户端打包好了,不存在此问题。看起来像是一个 bug。目前已向作者反馈问题,并期待作者进一步确认。 调试Wails依据Wails的官网:构建命令 中的提醒,能够在打包的时候退出-debug参数,在应用程序中保留调试信息。 容许在应用程序窗口中应用 devtools。 残缺的打包命令为: wails build -debug这样,能够在打包后的文件中持续应用浏览器调试模式来剖析排查(生产上不倡议增加-debug参数)。 问题复现我的项目中应用了vue3-cookies这个库,一开始认为是这个库的问题,于是我改用js原生办法: document.cookie = "username=John Doe; expires=" + new Date(new Date().getTime() + (24 * 60 * 60 * 1000)).toUTCString() + "; path=/";发现仍然存在以下景象(体现在MacOS下): wails dev开发者模式下一切正常,cookie设置胜利wails build编译后的包,cookies无奈设置和存储,也没有抛出谬误Wails环境和版本信息呈现这个BUG的环境信息如下: Wails CLI v2.4.1Scanning system - Please wait (this may take a long time)...Done.# SystemOS | MacOS Version | 13.3.1 ID | 22E261 Go Version | go1.20.3Platform | darwin Architecture | amd64 # WailsVersion | v2.4.1# DependenciesDependency | Package Name | Status | Version Xcode command line tools | N/A | Installed | 2397 npm | N/A | Installed | 9.5.0 *Xcode | N/A | Available | *upx | N/A | Installed | upx 4.0.2*nsis | N/A | Available | * - Optional Dependency问题反馈于是在给作者的我的项目提出了issues,见:https://github.com/wailsapp/wails/issues/2590 ...

April 16, 2023 · 1 min · jiezi

关于go:MatrixOne-logservice-原理解析

导读Logservice 在 MatrixOne 中扮演着十分重要的角色,它是独立的服务,通过RPC的形式供内部组件应用,用来对日志进行治理。 Logservice应用基于raft协定的dragonboat库(multi-raft group的golang开源实现),通常状况下应用本地磁盘,以多正本的形式保留日志,能够了解为对 WAL 的治理。事务的提交只须要写入Logservice中就能够,不须要将数据写入到S3,有另外的组件异步地将数据批量写入到S3上。这样的设计,保障了在事务提交时的低提早,同时多个正本也保障了数据的高牢靠。 本文将重点分享MatrixOne中 logservice 模块的次要原理。 上面是本文目录概览: 整体架构客户端服务端Write&ReadTruncationPart 1 整体架构如下图所示是 logservice 的整体架构。在 server 中包含 handler、dragonboat、以及 RSM 几个模块。 Part 2 客户端Logservice client 次要是提供给 DN 调用,要害接口阐明如下: Close() 敞开客户端连贯。Config() 获取 client 相干配置。GetLogRecord() 返回一个 pb.LogRecord 变量,该构造包含 8 字节的 Lsn,4 字节的 record type,以及类型为 []byte 的 Data。Data 局部包含 4 字节的 pb.UserEntryUpdate,8 字节的 replica DN ID,曾经 payload []byte。Append() append pb.LogRecord 到 logservice,返回值为 Lsn。在调用端,参数 pb.LogRecord 能够复用。Read() 从 logservice 中读取 firstLsn 开始的日志,达到 maxSize 时完结读取,返回值 Lsn 作为下一次读取的终点。Truncate() 删除 lsn 之前的日志,开释磁盘空间。GetTruncatedLsn() 返回最新删除的日志 Lsn。GetTSOTimestamp() 向 TSO 申请总数为 count 的工夫戳,调用之前的工夫戳,调用者占用 [returned value, returned value + count] 这个范畴。该办法暂未应用。Client 通过 MO-RPC 向 logservice 的 server 端发送申请,server 端与 raft/drgonboat 交互返回后果。 ...

April 14, 2023 · 3 min · jiezi

关于go:goeasyutils-20-正式发布全面支持泛型和any

介绍这是一个基于 Go 语言开发的通用数据类型解决工具类,帮忙开发者在业务代码实现中解决常见的数据类型和数据操作。能够让您专一于您的业务代码的实现,而免去解决根本数据类型转换和验证的性能。该工具库无侵入式的设计能够让您的业务代码更容易浏览和优雅。 疾速开始装置 应用 Go1.18 及以上版本的用户,倡议装置 v2.x.x。 因为 v2.x.x 利用 Go1.18 的泛型重写了大部分函数 go get -u github.com/jefferyjob/go-easy-utils应用 Go1.18 以下版本的用户,必须装置 v1.x.x。目前最新的 v1 版本是 v1.1.0 go get github.com/jefferyjob/go-easy-utils@v1.1.0应用Demo package mainimport ( "fmt" "github.com/jefferyjob/go-easy-utils/sliceUtil")func main() { var slice = []string{"this", "is", "go", "easy", "utils"} chunkSlice := sliceUtil.ChunkSlice(slice, 2) fmt.Printf("%v", chunkSlice)}性能列表jsonUtil Json解决工具// JsonToStruct 将 JSON 字符串解析为指定的构造体指针func JsonToStruct(jsonData string, result any) errorValidUtil 验证工具// IsTime 验证是否为工夫格局(HH:mm:ss)func IsTime(str string) bool// IsDate 验证是否为日期格局(yyyy-MM-dd)func IsDate(str string) bool// IsDateTime 验证是否为日期工夫格局(yyyy-MM-dd HH:mm:ss)func IsDateTime(str string) bool// IsIDCard 验证身份证号(18或15位)func IsIDCard(str string) bool// IsIDCard18 验证18位身份证号func IsIDCard18(id string) bool// IsIDCard15 验证15位身份证号func IsIDCard15(idCard string) bool// IsMobile 验证是否为手机号码func IsMobile(mobileNum string) bool // IsTelephone 验证是否为座机号码func IsTelephone(telephone string) bool // IsPostalCode 验证是否为邮编号码func IsPostalCode(str string) bool // IsDecimal 验证给定的字符串小数点后是否最多两位func IsDecimal(input string) bool // IsNumber 验证是否全副为数字func IsNumber(input string) bool// IsBankCardNo 验证是否为银行卡号func IsBankCardNo(str string) bool// IsAllChinese 验证给定的字符串全副为中文func IsAllChinese(input string) bool// IsContainChinese 验证给定的字符串蕴含中文func IsContainChinese(input string) bool// IsEmail 是否为emailfunc IsEmail(input string) bool// IsIPv4 是否为ipv4地址func IsIPv4(input string) bool// IsIPv6 是否为ipv6地址func IsIPv6(input string) bool// IsURL 是否为URL地址func IsURL(input string) bool// IsJSON 是否为Jsonfunc IsJSON(input string) bool// IsChineseName 验证是否为中文名func IsChineseName(name string) bool// IsEnglishName 验证是否为英文名func IsEnglishName(name string) bool// IsQQ 验证是否为QQ号func IsQQ(qq string) bool // IsWeChat 验证是否为微信号func IsWeChat(wechat string) bool// IsWeibo 验证是否为微博IDfunc IsWeibo(weibo string) bool// IsPassword 验证明码是否非法// 明码长度在6-20个字符之间,只蕴含数字、字母和下划线func IsPassword(password string) boolstrUtil 字符串工具// StrToInt string转intfunc StrToInt(v string) int// StrToInt8 string转int8func StrToInt8(v string) int8// StrToInt16 string转int16func StrToInt16(v string) int16// StrToInt32 string转int32func StrToInt32(v string) int32// StrToInt64 string转int64func StrToInt64(v string) int64// StrToUint string转uintfunc StrToUint(v string) uint// StrToUint8 string转uint8func StrToUint8(v string) uint8// StrToUint16 string转uint16func StrToUint16(v string) uint16// StrToUint32 string转uint32func StrToUint32(v string) uint32// StrToUint64 string转uint64func StrToUint64(v string) uint64// StrToBytes 字符串转字节数组func StrToBytes(v string) []byte sliceUtil 切片解决工具// Chunk 把slice宰割为新的数组块func ChunkSlice(slice []T, size int) [][]T// Column 获取slice中某个繁多列的值func ColumnSlice(slice []T, column string) []any// In 判断value是否在slice中func InSlice(value T, slices []T) bool// Is 判断指定值i是否是slice类型func IsSlice(slice any) bool// Merge 将多个slice合并成一个slicefunc MergeSlice(slices ...[]T) []T// Sum 对slice中的元素求和func SumSlice(slice []T) T// Unique 移除slice中反复的值func UniqueSlice(slice []T) []TmapUtil map类型解决// MapKeyExists 判断map中的key是否存在func MapKeyExists((m map[T]T2, key T)) bool// MapValueExists 判断map中的value是否存在func MapValueExists(m map[T2]T, value T) boolmathUtil// Abs 返回一个数的绝对值func Abs(num T) T// Ceil 对float数据向上取整func Ceil(num T) int// Floor 对float数据向下取整func Floor(num T) int// Max 返回slice中最大值func Max(slice []T) T// Min 返回slice中最小值func Min(slice []T) T// Round 对float数据四舍五入func Round(num T) intfloatUtil 浮点型解决// Float32ToStr float32转字符串func Float32ToStr(f float32) string// Float64ToStr float64转字符串func Float64ToStr(f float64) string// Float32ToFloat64 float32转float64func Float32ToFloat64(f float32) float64// Float64ToFloat32 float64转float32func Float64ToFloat32(f float64) float32emoji表情包// DecodeEmojiUnicode Emoji表情解码func DecodeEmojiUnicode(unicode string) string// EncodeEmojiUnicode Emoji表情编码func EncodeEmojiUnicode(emoji string) stringcryptoUtil 加密与解密// HashSHA256 hash加密func HashSHA256(str string) string// Md5 MD5加密func Md5(string string) stringbyteUtil 字节数组// BytesToStr 字节数组转字符串func BytesToStr(data []byte) stringanyUtil 任意类型转换// AnyToFloat32 将给定的值转换为float32func AnyToFloat32(i any) (float32, error)// AnyToFloat64 将给定的值转换为float64func AnyToFloat64(i any) (float64, error)// AnyToInt 将给定的值转换为 intfunc AnyToInt(i any) (int, error)// AnyToInt8 将给定的值转换为 int8func AnyToInt8(i any) (int8, error)// AnyToInt16 将给定的值转换为 int16func AnyToInt16(i any) (int16, error)// AnyToInt32 将给定的值转换为 int32func AnyToInt32(i any) (int32, error)// AnyToInt64 将给定的值转换为 int64func AnyToInt64(i any) (int64, error)// AnyToStr 任意类型数据转stringfunc AnyToStr(i any) string// AnyToUint 将给定的值转换为 uintfunc AnyToUint(i any) (uint, error)// AnyToUint8 将给定的值转换为 uint8func AnyToUint8(i any) (uint8, error)// AnyToUint16 将给定的值转换为 uint16func AnyToUint16(i any) (uint16, error)// AnyToUint32 将给定的值转换为 uint32func AnyToUint32(i any) (uint32, error)// AnyToUint64 将给定的值转换为 uint64func AnyToUint64(i any) (uint64, error)// AnyToBool 将给定的值转换为boolfunc AnyToBool(i any) bool

April 13, 2023 · 3 min · jiezi

关于go:2022最新极客Go实战训练营0期汨余若将不及兮恐年岁之不吾与

download:2022最新极客Go实战训练营0期在当今数字化时代,Web数据库是任何网站或应用程序的外围。它们能够存储和治理大量的数据,并且使得数据的拜访和操作变得非常容易和高效。本文将介绍Web数据库的基本概念、类型、长处和利用场景。 什么是Web数据库? Web数据库是指通过Web浏览器来拜访和治理的数据库。它们通常运行在Web服务器上,与Web应用程序相结合,提供数据存储和查问的性能。Web数据库也能够通过网络拜访,容许近程用户拜访和治理数据。 Web数据库的类型 Web数据库通常分为两种类型:关系型数据库和非关系型数据库。 关系型数据库关系型数据库采纳表格的模式存储数据,数据以行和列的模式进行组织。这些表格能够通过SQL查询语言进行拜访和操作。关系型数据库通常应用结构化查询语言(SQL)来查问和操作数据,例如MySQL、PostgreSQL和Oracle等。 非关系型数据库非关系型数据库则不应用表格的模式来存储数据。相同,它们应用键-值对或文档的模式来组织和存储数据。这些数据库通常具备更高的可扩展性和更好的性能,例如MongoDB和CouchDB等。 Web数据库的长处 Web数据库的长处非常明显,它们能够进步数据管理和拜访的效率。以下是Web数据库的长处: 高效的数据管理Web数据库容许用户轻松地存储和治理数据。这些数据能够以多种格局进行组织和存储,例如表格、键-值对和文档等。此外,Web数据库还能够提供高级数据处理性能,例如数据查问、排序、过滤和分组等。 多用户拜访Web数据库能够反对多个用户同时拜访和操作同一数据。这是十分重要的,特地是对于企业和团队来说,能够大大提高团队单干的效率。 可扩展性Web数据库能够轻松扩大以适应一直增长的数据需要。这些数据库能够通过增加新的硬件、减少存储空间或者分布式架构来扩大。 Web数据库的利用场景 Web数据库广泛应用于各种行业和畛域,例如: 电子商务Web数据库能够用于存储和治理电子商务网站的产品和订单数据。这些数据能够不便地进行治理和查问,使得网站能够提供更高效的服务。 社交媒体Web数据库能够用于存储和治理社交媒体网站的用户信息、帖子和评论等数据。这些数据能够不便地进行查问和剖析,

April 13, 2023 · 1 min · jiezi

关于go:Go是一门面向对象编程语言吗

本文首发自「慕课网」,想理解更多IT干货内容,程序员圈内热闻,欢送关注"慕课网"! 作者:tonybai|慕课网讲师 Go语言曾经开源13年了,在近期TIOBE公布的2023年3月份的编程语言排行榜中,Go再次冲入前十,相较于Go在2022年底的排名晋升了2个位次:这些年对于Go在这两年开始飞起的“预言”也正在逐渐成为事实_,大家学习Go的激情也在疾速晋升。很多读者都是第一次接触Go,你们中的很多是来自像Java, Ruby这样的OO(面向对象)语言营垒的,很多童鞋学习Go之后的第一个问题便是:Go是一门OO语言吗?在这篇博文中,咱们就来探讨一下。 一. 溯源在公认的Go语言“圣经”《Go程序设计语言》一书中,有这样一幅Go语言与其次要的先祖编程语言的亲缘关系图: 从图中咱们能够清晰看到Go语言的“继承脉络”: 从C语言那里借鉴了表达式语法、管制语句、根本数据类型、值参数传递、指针等;从Oberon-2语言那里借鉴了package、包导入和申明的语法,而Object Oberon提供了办法申明的语法。从Alef语言以及Newsqueak语言中借鉴了基于CSP的并发语法。咱们看到,从Go先祖溯源的状况来看,Go并没有从纯面向对象语言比方Simula、SmallTalk等那里取经。Go诞生于2007年,开源于2009年,那正是面向对象语言和OO范式大行其道的期间。不过Go设计者们感觉经典OO的继承体系对程序设计与扩大仿佛并无太多益处,还带来了较多的限度,因而在正式版本中并没有反对经典意义上的OO语法,即基于类和对象实现的封装、继承和多态这三大OO支流个性。 但这是否阐明Go不是一门OO语言呢?也不是! 带有面向对象机制的Object Oberon也是Go的先祖语言之一,尽管Object Oberon的OO语法又与咱们明天常见的语法有较大差别。 就此问题,我还特意征询了ChatGPT_,失去的回答如下: ChatGPT认为:Go反对面向对象,提供了对面向对象范式基本概念的反对,但反对的伎俩却并不是类与对象。 那么针对这个问题Go官网是否有回应呢? 有的,咱们来看一下。 二. 官网声音 Go官网在FAQ中就Go是否是OO语言做了简略回应: Is Go an object-oriented language?Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of “interface” in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing. Moreover, methods in Go are more general than in C++ or Java: they can be defined for any sort of data, even built-in types such as plain, “unboxed” integers. They are not restricted to structs (classes).Also, the lack of a type hierarchy makes “objects” in Go feel much more lightweight than in languages such as C++ or Java.粗略翻译过去就是: ...

April 12, 2023 · 2 min · jiezi

关于go:Go-语言体系下的微服务框架选型Dubbogo

01 Go 微服务体系倒退与选型随着微服务技术的疾速倒退,其在各个领域都造成了一系列事实标准,在 Kubernetes 和容器技术加持下,云原生微服务曾经成为了支流解决方案。而 Go 语言作为云原生畛域最受欢迎的开发语言,正被越来越多的企业作为微服务开发的首选语言,其中比拟风行的包含 Go-micro、Go-zero、Dubbo-go 等。作为 Dubbo 微服务体系中多语言实现的一员,在 2022 年 Dubbo-go 以微服务领跑者的角色踊跃拥抱云原生规范,摸索了 Proxyless Mesh 状态,配合适配 Pixiu 云原生网关,造成了欠缺的 Dubbo-go 微服务生态矩阵。 以 Dubbo-go 为核心的微服务体系在多个知名企业中胜利落地和实际,框架的稳定性在理论场景下禁受住了考验。截止往年已有 60+ 家企业在咱们的用户列表中注销,其中较为典型案例请参考文章《小米电商 Apache Dubbo-go 微服务实际》。小米电商选用了 Dubbo-go + Nacos + sidecar + etcd + mirpc 为外围的微服务体系,除了看中了 Dubbo-go 的互联互通和服务治理能力外,也认可 Dubbo-go 在微服务方向的积淀和积攒。 02 Dubbo-go 简介2.1 什么是 Dubbo-goApache Dubbo 是一款易用、高性能的 WEB 和 RPC 框架,同时为构建企业级微服务提供服务发现、流量治理、可观测、认证鉴权等能力、工具与最佳实际。Dubbo3 从设计上不绑定编程语言,社区目前提供了 Java、Go、Rust、Node.js 等多语言实现,在将来,咱们打算为所有支流语言提供对等的微服务开发体验。 Dubbo 框架作为国内最具影响力的开源微服务开发框架之一,领有十分高的关注度和活跃度,在 GitHub 上领有 3.8 万+ stars。Dubbo 我的项目于 2017 年捐献给 Apache 基金会,在经验了短短 15 个月孵化后顺利毕业,在 Apache 基金会治理的全副我的项目中关注度排名第三(前两名别离是 echarts 和 superset),Dubbo-go 作为 Dubbo 多语言生态的重要一员,很好的兼容 Dubbo 生态的同时提供面向 Go 语言体系的微服务开发体验。 ...

April 11, 2023 · 3 min · jiezi

关于go:如何用Golang处理每分钟100万个请求

用Golang解决每分钟100万个申请转载请注明起源:https://janrs.com/9yaq面临的问题在我设计一个剖析零碎中,咱们公司的指标是可能解决来自数百万个端点的大量POST申请。web 网络处理程序将收到一个JSON文档,其中可能蕴含许多有效载荷的汇合,须要写入Amazon S3,以便咱们的地图还原零碎随后对这些数据进行操作。 传统上,咱们会钻研创立一个工人层架构,利用诸如以下货色: SidekiqResqueDelayedJobElasticbeanstalk Worker TierRabbitMQ还有等等其余的技术手段...并设置 2 个不同的集群,一个用于 Web 前端,另一个用于 worker 解决过程,这样咱们就能够扩充咱们能够解决的后盾工作量。 但从一开始,咱们的团队就晓得咱们应该在 Go 中这样做,因为在探讨阶段咱们看到这可能是一个十分大的流量零碎。 我应用 Go 已有大概 2 年左右的工夫,咱们公司在解决业务时开发了一些零碎,但没有一个能接受如此大的负载。以下是优化的过程。 咱们首先创立一些构造体来定义咱们将通过 POST 调用接管的 Web 申请负载,以及一种将其上传到咱们的 S3 存储桶的办法。代码如下: type PayloadCollection struct { WindowsVersion string `json:"version"` Token string `json:"token"` Payloads []Payload `json:"data"`}type Payload struct { // ...负载字段}func (p *Payload) UploadToS3() error { // storageFolder 办法确保在咱们在键名中取得雷同工夫戳时不会产生名称抵触 storage_path := fmt.Sprintf("%v/%v", p.storageFolder, time.Now().UnixNano()) bucket := S3Bucket b := new(bytes.Buffer) encodeErr := json.NewEncoder(b).Encode(payload) if encodeErr != nil { return encodeErr } // 咱们公布到 S3 存储桶的所有内容都应标记为“公有” var acl = s3.Private var contentType = "application/octet-stream" return bucket.PutReader(storage_path, b, int64(b.Len()), contentType, acl, s3.Options{})}应用 Go 协程最后咱们采纳了一个非常简单的 POST 处理程序实现,只是试图将job 处理程序并行化到一个简略的 goroutine 中: ...

April 11, 2023 · 3 min · jiezi

关于go:Excelize-发布-271-版本Go-语言-Excel-文档基础库

Excelize 是 Go 语言编写的用于操作 Office Excel 文档根底库,基于 ECMA-376,ISO/IEC 29500 国际标准。能够应用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创立的电子表格文档。反对 XLAM / XLSM / XLSX / XLTM / XLTX 等多种文档格局,高度兼容带有款式、图片(表)、透视表、切片器等简单组件的文档,并提供流式读写 API,用于解决蕴含大规模数据的工作簿。可利用于各类报表平台、云计算、边缘计算等零碎。入选 2020 Gopher China - Go 畛域明星开源我的项目(GSP)、2018 年开源中国码云最有价值开源我的项目 GVP (Gitee Most Valuable Project),目前已成为 Go 语言最受欢迎的 Excel 文档根底库。 开源代码GitHub: github.com/xuri/excelize Gitee: gitee.com/xurime/excelize 中文文档: xuri.me/excelize/zh-hans 2023年4月10日,社区正式公布了 2.7.1 版本,该版本蕴含了多项新增性能、谬误修复和兼容性晋升优化。上面是无关该版本更新内容的摘要,残缺的更改列表可查看 changelog。 此版本中最显著的变动包含: 兼容性提醒移除了 ChartLine 数据类型中的 Color 字段应用 RichTextRun 数据类型代替 ShapeParagraph应用 Fill 代替 Shape 数据类型中的 Color 字段移除了已导出的数据类型 AutoFilterListOptions将数据类型 TableOptions 重命名为 Table增加图表函数 AddChart 改为应用 ChartType 类型枚举值指定图表类型批改了 7 个函数的签名,具体更改详见官网文档中的更新阐明新增性能新增函数 SetSheetDimension 与 GetSheetDimension 以反对设置与获取工作表已用区域,相干 issue #1463创立款式函数 NewStyle 现已反对 17 种突变填充款式减少创立款式数量下限至 65430通过 AddPicture 增加图片时,现已容许插入 BMP 格局图片函数 GetPictures 反对读取被增加至同一单元格中的多张图片设置条件格局函数 SetConditionalFormat 反对设置带有“如果为真则进行”和“图标集”条件的条件格局规定设置条件格局函数 SetConditionalFormat 反对设置在条件格局中应用带有纯色填充款式的数据条,并反对指定数据条的色彩,相干 issue #1462增加图表函数 AddChart 反对设置图表中各个数据系列应用自定义填充色彩,相干 issue #1474增加图表函数 AddChart 反对设置气泡图图表中各个系列气泡的大小增加图表函数 AddChart 反对设置子母饼图和复合条饼图中第二绘图区域的数据系列增加图表函数 AddChart 反对为图表中数据标签设置自定义数字格局,相干 issue #1499创建表格函数 AddTable 反对在创建表格时指定是否蕴含题目行创建表格函数 AddTable 创建表格时减少对表格名称的校验,并导出了谬误常量 ErrTableNameLength,相干 issue #1468函数 AutoFilter 反对为筛选范畴内的多个列设置筛选条件计算单元格的值函数 CalcCellValue 现已反对指定是否为公式计算结果利用数字格局计算单元格的值函数 CalcCellValue 对于以下公式函数退出了双字节字符的反对:LEFT, LEN, LENB, MID, MIDB, RIGHT 和 RIGHTB,相干 issue #1476计算单元格的值函数 CalcCellValue 函数对于存在谬误的公式将在计算结果中返回公式错误代码,并将具体错误信息在 error 数据类型的返回值中返回,相干 issue #1490对输出图片文件的扩展名调整为大小写不敏感,相干 issue #1503应用流式写入器流式按行赋值时,对于值为 nil 的单元格将会跳过生成该单元格,相干 issue #756获取超链接 GetCellHyperLink 函数反对读取合并单元格中的超链接增加了新的导出类型 ChartType 以示意图表类型枚举兼容性晋升兼容带有函数组的工作簿兼容带有严格模式 XML 命名空间地址的工作簿主题,相干 issue #1447进步了与文档外部不含工作簿关系部件工作簿的兼容性,以修复关上此类工作簿可能呈现的 panic问题修复修复了特定状况下读取日期工夫类型单元格的值存在精度误差的问题修复了特定状况下当批改本来存储了日期工夫类型的单元格为文本类型值,批改后单元格数据类型有误的问题,解决 issue #1464修复了局部状况下公式计算结果为空的问题,解决 issue #1469修复了设置数据条类型条件格局时,指定自定义最大/最小值有效的问题,解决 issue #1492修复了关上行高或列宽为 0 的工作表,保留后行高列宽设置生效的问题,解决 issue #1461进步了读取带有空白字符共享字符串表索引值的兼容性,解决 issue #1508性能优化进步了利用带有自定义月份数字格局的速度,相干 issue #1455大幅提高了对于带有合并单元格工作表的处理速度,相干 issue #1448其余Go Excelize 提供了反对 WebAssembly / Javascript 环境的 excelize-wasm NPM 包Go Modules 依赖模块更新单元测试与文档更新优化外部变量与函数命名蕴含简体中文、英语、法语、俄语、日语、韩语、阿拉伯语、德语和西班牙语的多国语言文档网站更新致谢感激 Excelize 的所有贡献者,以下是为此版本提交代码的贡献者列表: ...

April 10, 2023 · 1 min · jiezi

关于go:不想做架构师的Gopher不是好程序员

最近咱们在组队学习《手把手带你写一个web框架》,强制PUSH,保持每天学习打卡,不实现惩办发红包的那种。 你别说,成果还真挺好。 昨天学到了架构局部,很受启发,光学不写假把式。(还是得保持输入哇)我站在大佬的肩膀上输入一篇总结文章进去,心愿对大家有帮忙: 概述所谓架构,与一线开发最大的不同就在于是否有零碎设计工作。架构师的价值曾经不再体现在编码实现上,而更多地体现在设计上。 本文将重点介绍业务架构师和根底架构师的工作内容和职责,以及在架构设计中的重要性和作用。 业务架构师和根底架构师的职责根底架构师次要负责根底服务的架构设计,这些服务是和业务无关的,包含数据库、缓存、队列等简直所有业务都会应用到的服务。而业务架构师则次要负责让技术更好地服务业务。 在架构设计中,实现一个性能的办法有很多种,然而最合乎本身业务的技术选型才是最优的。因而,业务架构师必须理解业务特点和需要,从而做出最优的技术决策。而根底架构师则须要深刻理解根底服务的特点和性能,以及如何为业务提供最优的基础架构反对。 单干与沟通对于技术人员而言,最终的技术能力模型应该是一个大T字形,即在某个畛域有足够的深度,在多个畛域有足够的广度。因而,尽管根底架构师和业务架构师具备不同的技术背景和业余畛域,但两者之间的交换和单干至关重要。只有通过单干,能力确保零碎的整体性和稳定性。 不论你的能力有多强,接手新的业务时,前三个月尽量不要做大的架构级别的批改,因为不熟悉业务,没有足够工夫理解一线的代码逻辑,是不可能做出好的架构调整的。 架构设计中的准则和法则基础架构的同学更大可能是往技术专家方向倒退。他们对技术的成就感更多来源于为某个软件或某种语言减少个性,比方会谋求成为 Apache PMC、微软的 MVP 等。他们的钻研有可能扭转某个技术行业。如果想走这个方向,必须热衷于某个技术行业。 《零碎架构 - 简单零碎的产品设计与开发》这本书通知读者如何做出一套思考零碎架构的形式,即一些思考零碎的准则和定律。整顿一下对我有启发的准则: 歧义准则:零碎架构的晚期阶段充斥了歧义。架构师必须解决这种歧义,以便给架构团队定出指标并继续更新该指标。架构师角色准则:架构师的角色是解决歧义,专一翻新,并简化复杂度。架构决策准则:要把架构决策和其余决策离开,并且要提前花一些工夫来审慎地决定这些问题,因为当前如果要想变更会付出很大的代价。Conway 定律:设计零碎的组织,总是会产生出与该组织的沟通构造雷同的设计。产品进化准则:零碎必须进化,否则就会失去竞争力。因而,在架构设计中,必须思考零碎的可扩展性和可维护性,以适应将来业务的变动和倒退。2下1上准则:要想判断对level1所做的合成是否适合,必须再向下合成一层,以确定level2中的各种关系。这些准则和法则对于架构师的工作十分有帮忙,能够帮忙他们更好地了解零碎架构,做出更优良的设计。 论断总之,业务架构和基础架构在架构设计中扮演着不同的角色和职责,但两者之间的单干是十分必要的。 架构师必须具备足够的技术深度和广度,以及良好的沟通和单干能力,能力为企业构建持重和牢靠的零碎架构。

April 10, 2023 · 1 min · jiezi

关于go:Go-语言切片是如何扩容的

原文链接: Go 语言切片是如何扩容的? 在 Go 语言中,有一个很罕用的数据结构,那就是切片(Slice)。 切片是一个领有雷同类型元素的可变长度的序列,它是基于数组类型做的一层封装。它非常灵活,反对主动扩容。 切片是一种援用类型,它有三个属性:指针,长度和容量。 底层源码定义如下: type slice struct { array unsafe.Pointer len int cap int}指针: 指向 slice 能够拜访到的第一个元素。长度: slice 中元素个数。容量: slice 起始元素到底层数组最初一个元素间的元素个数。比方应用 make([]byte, 5) 创立一个切片,它看起来是这样的: 申明和初始化切片的应用还是比较简单的,这里举一个例子,间接看代码吧。 func main() { var nums []int // 申明切片 fmt.Println(len(nums), cap(nums)) // 0 0 nums = append(nums, 1) // 初始化 fmt.Println(len(nums), cap(nums)) // 1 1 nums1 := []int{1,2,3,4} // 申明并初始化 fmt.Println(len(nums1), cap(nums1)) // 4 4 nums2 := make([]int,3,5) // 应用make()函数结构切片 fmt.Println(len(nums2), cap(nums2)) // 3 5}扩容机会当切片的长度超过其容量时,切片会主动扩容。这通常产生在应用 append 函数向切片中增加元素时。 ...

April 9, 2023 · 5 min · jiezi

关于go:Go接口运维开发场景中go的接口到底怎么用

golang的接口是什么在 Golang 中,接口是一种类型,它是由一组办法签名组成的形象汇合。接口定义了对象应该具备的行为,而不关怀对象的具体实现。实现接口的对象必须实现接口定义的所有办法,这样能力称为该接口的实现。 什么状况下要用接口定义通用的办法:接口能够定义一组通用的办法,以便在不同类型中实现。这样能够让代码更加通用,缩小冗余。比方,文件系统中的 Read 和 Write 办法就是一种通用的办法,能够在不同类型的文件对象上实现。另一个例子是 fmt.Stringer 接口,它定义了一个 String() 办法,能够返回一个字符串示意对象。实现多态:接口能够实现多态,也就是在不同类型的对象上执行雷同的操作。通过接口,不同类型的对象能够实现雷同的接口,从而在执行雷同的操作时,能够调用不同类型的对象的办法。例如,io.Reader 和 io.Writer 接口能够用来读取和写入数据,不同类型的对象能够实现这些接口,从而能够应用雷同的代码来解决不同类型的数据。松耦合的设计:接口能够实现松耦合的设计,也就是在接口的定义中,只定义了对象应该具备的行为,而不关怀对象的具体实现。这使得咱们能够轻松地替换对象的实现,而不用放心其余局部的代码会受到影响。例如,在测试中,咱们能够应用模仿对象来替换实在的对象,从而测试代码的逻辑,而不用放心对其余局部的代码产生影响。实现插件化架构:应用接口能够实现插件化架构,也就是将代码合成为小的模块,每个模块实现一个或多个接口。这样能够使得代码更加灵便,能够在运行时动静加载和卸载模块。例如,一个应用程序能够定义一个插件接口,其余开发人员能够编写插件并实现该接口,从而能够将这些插件动静地加载到应用程序中。应用接口能够进步代码的灵活性和可重用性,从而缩小代码的冗余和进步代码的可维护性。在 Golang 中,接口是一种十分弱小和灵便的个性,倡议在开发中宽泛应用。实战案例多态的例子场景:在运维开发中,可能须要治理不同类型的服务器,如物理服务器、虚拟机和容器。这些服务器可能具备不同的属性和治理办法。在这种状况下,能够应用接口来实现多态,从而在不同类型的服务器上执行雷同的操作。package main// 定义服务器接口type Server interface {    GetName() string    GetIP() string    Reboot() error    InstallPackage(name string) error}// 物理服务器实现type PhysicalServer struct {    Name string    IP   string    // 其余物理服务器的属性}func (s *PhysicalServer) GetName() string {    return s.Name}func (s *PhysicalServer) GetIP() string {    return s.IP}func (s *PhysicalServer) Reboot() error {    // 应用IPMI等技术重启物理服务器的具体实现    return nil}func (s *PhysicalServer) InstallPackage(name string) error {    // 应用yum、apt等工具装置软件包的具体实现    return nil}// 虚拟机实现type VirtualMachine struct {    Name string    IP   string    // 其余虚拟机的属性}func (s *VirtualMachine) GetName() string {    return s.Name}func (s *VirtualMachine) GetIP() string {    return s.IP}func (s *VirtualMachine) Reboot() error {    // 应用虚拟化管理工具重启虚拟机的具体实现    return nil}func (s *VirtualMachine) InstallPackage(name string) error {    // 应用操作系统的包管理工具装置软件包的具体实现    return nil}// 容器实现type Container struct {    Name string    IP   string    // 其余容器的属性}func (s *Container) GetName() string {    return s.Name}func (s *Container) GetIP() string {    return s.IP}func (s *Container) Reboot() error {    // 应用容器管理工具重启容器的具体实现    return nil}func (s *Container) InstallPackage(name string) error {    // 应用容器管理工具装置软件包的具体实现    return nil}// 主函数中应用不同类型的服务器对象func main() {    // 创立不同类型的服务器对象    physicalServer := &PhysicalServer{}    virtualMachine := &VirtualMachine{}    container := &Container{}    // 调用不同类型的服务器对象的办法    err := physicalServer.InstallPackage("nginx")    if err != nil {        // 处理错误    }    err = virtualMachine.Reboot()    if err != nil {        // 处理错误    }    err = container.InstallPackage("mysql")    if err != nil {        // 处理错误    }}定义通用办法的例子场景:一个常见的运维场景是治理多个服务器上的过程。在这种状况下,能够定义一个Process接口,它蕴含启动、进行和重启过程的办法。这个接口能够在不同类型的过程对象中实现,如Docker容器、操作系统过程或Kubernetes中的Pod。// 定义过程接口type Process interface {    Start() error    Stop() error    Restart() error}// 容器过程实现type ContainerProcess struct {    ContainerID string    // 其余容器过程的属性}func (c *ContainerProcess) Start() error {    // 应用Docker API 启动容器过程的具体实现    return nil}func (c *ContainerProcess) Stop() error {    // 应用Docker API 进行容器过程的具体实现    return nil}func (c *ContainerProcess) Restart() error {    // 应用Docker API 重启容器过程的具体实现    return nil}// 操作系统过程实现type OSProcess struct {    PID int    // 其余操作系统过程的属性}func (o *OSProcess) Start() error {    // 应用零碎API 启动操作系统过程的具体实现    return nil}func (o *OSProcess) Stop() error {    // 应用零碎API 进行操作系统过程的具体实现    return nil}func (o *OSProcess) Restart() error {    // 应用零碎API 重启操作系统过程的具体实现    return nil}// Kubernetes Pod 实现type KubernetesPod struct {    PodName string    // 其余Kubernetes Pod 的属性}func (k *KubernetesPod) Start() error {    // 应用 Kubernetes API 启动 Pod 过程的具体实现    return nil}func (k *KubernetesPod) Stop() error {    // 应用 Kubernetes API 进行 Pod 过程的具体实现    return nil}func (k *KubernetesPod) Restart() error {    // 应用 Kubernetes API 重启 Pod 过程的具体实现    return nil}// 主函数中应用不同类型的过程对象func main() {    // 创立不同类型的过程对象    container := &ContainerProcess{}    osProcess := &OSProcess{}    kubernetesPod := &KubernetesPod{}    // 调用不同类型的过程对象的办法    err := container.Start()    if err != nil {        // 处理错误    }    err = osProcess.Stop()    if err != nil {        // 处理错误    }    err = kubernetesPod.Restart()    if err != nil {        // 处理错误    }}这个示例代码演示了如何在不同类型的过程对象中实现Process接口。因为Process接口定义了一组通用的办法,能够通过一个通用的函数或工具类来治理不同类型的过程对象,从而缩小冗余的代码。 松耦合的例子场景:在运维开发中,假如要治理不同的云平台服务,例如腾讯云、阿里云、挪动云等。每个云平台提供的服务可能会有不同的实现形式和API接口,然而它们都具备类似的行为和性能,例如创立、删除、启动和进行服务实例,获取实例的状态和日志等。在这种状况下,咱们能够应用Go语言的接口来实现松耦合的设计,将不同云平台的服务实现封装在各自的构造体中,并且让它们都实现雷同的接口。这样,咱们的代码就能够应用雷同的函数来解决所有不同的云平台服务,而不用关怀具体的实现细节。package main// 定义CloudService接口type CloudService interface {    CreateInstance() error    DeleteInstance() error    StartInstance() error    StopInstance() error}// 腾讯云服务实现type TencentCloudService struct {    // 实现TencentCloudService特定的属性和办法}func (tencent *TencentCloudService) CreateInstance() error {    // 应用腾讯云 API 创立服务实例的具体实现    return nil}func (tencent *TencentCloudService) DeleteInstance() error {    // 应用腾讯云 API 删除服务实例的具体实现    return nil}func (tencent *TencentCloudService) StartInstance() error {    // 应用腾讯云 API 启动服务实例的具体实现    return nil}func (tencent *TencentCloudService) StopInstance() error {    // 应用腾讯云 API 进行服务实例的具体实现    return nil}// 阿里云服务实现type AliCloudService struct {    // 实现AliCloudService特定的属性和办法}func (ali *AliCloudService) CreateInstance() error {    // 应用阿里云 API 创立服务实例的具体实现    return nil}func (ali *AliCloudService) DeleteInstance() error {    // 应用阿里云 API 删除服务实例的具体实现    return nil}func (ali *AliCloudService) StartInstance() error {    // 应用阿里云 API 启动服务实例的具体实现    return nil}func (ali *AliCloudService) StopInstance() error {    // 应用阿里云 API 进行服务实例的具体实现    return nil}// 挪动云服务实现type MobileCloudService struct {    // 实现MobileCloudService特定的属性和办法}func (mobile *MobileCloudService) CreateInstance() error {    // 应用挪动云 API 创立服务实例的具体实现    return nil}func (mobile *MobileCloudService) DeleteInstance() error {    // 应用挪动云 API 删除服务实例的具体实现    return nil}func (mobile *MobileCloudService) StartInstance() error {    // 应用挪动云 API 启动服务实例的具体实现    return nil}func (mobile *MobileCloudService) StopInstance() error {    // 应用挪动云 API 进行服务实例的具体实现    return nil}// 主函数中应用不同的云服务实现func main() {    // 创立不同的云服务实现    tencentCloud := &TencentCloudService{}    aliCloud := &AliCloudService{}    mobileCloud := &MobileCloudService{}    // 接着就能够调用服务实现的办法...    }实现插件化架构的例子场景:假如有一个监控零碎,须要实现不同类型的监控插件 CPU 监控插件,能够获取 CPU 使用率。磁盘监控插件,能够获取磁盘应用状况。内存监控插件,能够获取内存应用状况。 咱们将编写一个主程序,以及三个插件,每个插件实现一个名为 Monitor 的接口,用于获取监控数据。编写主程序package mainimport ( "fmt" "plugin")type Monitor interface { GetData() (string, error)}func main() { // 加载插件 p, err := plugin.Open("./cpu_monitor.so") if err != nil {  panic(err) } // 获取插件实例 dataSourceSymbol, err := p.Lookup("CpuMonitorInstance") if err != nil {  panic(err) } dataSource, ok := dataSourceSymbol.(Monitor) if !ok {  panic("plugin does not implement DataSource") } // 应用插件获取数据 data, err := dataSource.GetData() if err != nil {  panic(err) } fmt.Println(data)}主程序定义了一个名为 Monitor 的接口,用于获取监控数据。在 main 函数中,咱们先加载一个名为 cpu_plugin.so 的插件,而后获取插件实例,并将其强制转换为 Monitor 接口类型。接下来,咱们调用 GetData 办法获取 CPU 监控数据,并输入到控制台。 编写插件 上面是一个名为 cpu_plugin.go 的插件,它实现了 Monitor 接口,用于获取 CPU 监控数据。package mainimport ( "fmt" "time")type CpuMonitor struct{}func (m CpuMonitor) GetData() (string, error) { // 模仿获取 CPU 使用率 usage := fmt.Sprintf("CPU usage: %d%%", 30) time.Sleep(time.Second) return usage, nil}var CpuMonitorInstance CpuMonitor在插件中,咱们实现了 Monitor 接口,并定义了一个名为 CpuMonitorInstance 的变量,用于导出插件实例。 编译插件 应用以下命令将插件编译为共享对象文件:go build -buildmode=plugin -o cpu_monitor.so cpu_monitor.go运行看看成果,发现曾经胜利加载插件[root@workhost temp]# go run main.go CPU usage: 30%编写内存、磁盘的监控插件也是按这个套路实现即可。留神了,我这里获取cpu使用率的插件只是模仿代码,并没有真正实现。实际上,能够应用Golang规范库中的runtime包就能够获取到cpu使用率。本文转载于WX公众号:不背锅运维(喜爱的盆友关注咱们):https://mp.weixin.qq.com/s/bwkK3Yw02w4szwub2B2-ig

April 8, 2023 · 1 min · jiezi

关于go:极客时间Go实战训练营1期202316周皎皎空中孤月轮

download:极客工夫-Go实战训练营1期-2023-16周Linux概述 Linux(UNIX)零碎是一种通用的多用户操作系统,它可能杰出地实现一般单用户、多用户操作系统所能实现的功能,为用户提供较好的利用界面和软件开发环境。 控制台和终端机 在UNIX零碎中,可能反对控制台与用户终端这两种前端机同时工作。 控制台是永远与主机相连的前端机,供系统管理员使用,次要浮现零碎运行信息,如零碎谬误、提示信息等等。 普通用户用一台用户终端机与主机零碎进行信息交互,终端机可能是一台具备处理能力的计算机,也可能是不具备处理能力的图形终端。Linux还使用虚构终端。 用户的注册与登记 在多用户分时系统中,为了满足多个用户在零碎中的管理工作,需要实现系统资源的共享和保护功能 。 帐号的概念 用户进入零碎之前必须向系统管理员申请一个账户,用下列形式注册登录到零碎中: Login:用户注册名Password:用户登录口令用户登录时的用户口令一般由6-8个字符形成,可包含字母、数字及其他字符。UNIX零碎中shell的默认命令行提示符,容许用户修改。 用户的口令在用户注册时由系统管理员指定,在当前的工作中容许用户自行修改,例如键入passwd命令可能修改用户口令: #passwd New Password: /键入新的登录的口令/ Retype New Password:**/重复新的口令/ 以上过程是超级用户修改口令的过程,对于普通用户: %passwd current password:*****/键入原有的登录的口令/ New Password:******/*键入新的口令*/ Retype New Password:.******/*再键入以上新口令,供零碎必定*/ 用户离开Linux(UNIX)零碎时,应进行登记(logout )操作。登记后的用户终端可提供应其余用户使用。 “登记”也告诉了正在进行中的零碎记账程序停止对该用户的记账工作。有多种形式实现用户登记,如: %logout /在命令行输出logout示意退出登录*/ %exit /*用终止当行过程执行的形式退出用户登录的过程/ % Ctrl-d /*用退出shell主过程的形式登记用户*/ 用户登记后零碎回到“Login”提示符下等待下一次用户的登录。通常在用户下次进行登录时,零碎会提供一些报告给用户查阅,例如用户最近一次注册的工夫和使用的终端信息。 账户的治理 因为Linux(UNIX)零碎是多用户零碎,零碎中每个用户并不能随心所欲地占用计算机系统资源。用户程序的执行是由操作系统按照肯定的外部治理规范和策略对立进行调配的。 零碎中记录的用户“账户”信息是零碎为用户占用系统资源而进行资源分配的基本数据,同时也是记录和组织用户在操作系统中流动的基础信息。Linux(UNIX)零碎次要使用四个文件,用来存放用户账户治理无关的数据信息,即:/etc/passwd, /etc/shadow, /etc/group,/etc/gshadow。 ◆/etc/passwd:零碎中所有被授权的用户都在该文件中占有一个记录项 username:*:uid:gid:comment:homedir:loginshell ① ②③ ④ ⑤ ⑥ ⑦ ①—用户名,指用户注册时输出的名字。 ②—口令,用户注册的口令以加明码形式保存,容许用户修改。 ③—用户标识符uid,系统管理中使用的用户标识。 ④—用户的组标识gid,用户所属组的惟一标识,一个用户可能属于一个或多个用户组。 ⑤—对注册用户的描述文本,是用户情况的基本简介,文本长度有肯定的申请,也可能省略此项。 ⑥—用户注册目录或用户主目录,此目录是用户进入零碎后首先进入的当前工作目录。 ⑦—进入零碎后第一步实现的内容,示意当用户进入零碎后,首先要执行的程序名。一般都将此项定义为用户进入零碎后抉择执行的shell程序。 例如:对某一必定的注册用户zhang,此项记录中的内容可能是: Zhang:*:103: 100:Zhang HongLi:/home/zhang: /bin/csh 在Linux(UNIX)零碎中,零碎程序根据记录中用户的‘账户’信息进行用户身份甄别和资源使用权的调配。在账户治理中有两大类型,一种是超级用户账户,另一种是普通用户账户。 超级用户账户具备零碎的高级管理权,可读、写、处理零碎中任意的一个文件,或者实现零碎的各种特定操作。超级用户账户一般只调配给系统管理员,使用特定的“root”超级用户名和设定的特定口令进入零碎。 对于自己公有的失密性很强的利用数据和信息,可能使用编程手段对系统管理员进行屏蔽。例如财务管理、人事管理中的无关信息,即便是系统管理员也不应该有拜访这些信息的权限,这些限度应该在利用零碎的设计中实现。 ...

April 7, 2023 · 1 min · jiezi

关于go:goalng-如何获取-ldap-服务器的数据

咱们工作在和其余组织配合时,咱们可能不是作为服务器搭建的一方,而是属于客户端的一方,须要去获取服务器的组织构造,依照某些条件去获取服务器的数据,也能够是同步组织构造 尽管说 golang 的数据结构没有 c++ 那么丰盛,不过对于这个 ldap 还是有相应的库来进行解决的 官网文档地址:https://pkg.go.dev/gopkg.in/ldap.v3 咱们也能够下载 github 下面的这个库 go get github.com/go-ldap/ldap/v3golang 对于 ldap 库最新的版本是 Version: v3.1.0 开始编码咱们来写一个 demo ,获取咱们上次搭建的 ldap 服务器上的组织构造 这是咱们简略搭建的 ldap 服务器,能够应用 LDAP Admin 可视化管理工具来查看具体的页面成果 咱们把这个库下载下来后,咱们的编码思路如下: 填写 ldap 服务器地址以及填写相应的管理员信息,与 ldap 服务器建设连贯编写查问申请,并开始向 ldap 服务器进行查问将查问构造,依照 ldap v3 库提供的形式 打印出成果来连贯 服务器咱们能够应用 func DialURL(addr string, opts ...DialOpt) (*Conn, error) 函数来与 ldap 服务器建设连贯 ml, err := ldap.DialURL("ldap://xxxx") if err != nil { log.Fatal(err) } defer ml.Close()咱们填入的地址中,能够不必输出端口号,库函数曾经有给咱们做好解决,咱们能够来看看源码 ...

April 6, 2023 · 2 min · jiezi

关于go:GoLang操作Json

GoLang 操作JSON数组dataJson := `["1","2","3"]`var arr []string_ = json.Unmarshal([]byte(dataJson), &arr)log.Printf("Unmarshaled: %v", arr)如何在 Golang 中解析 JSON 数组?

April 3, 2023 · 1 min · jiezi

关于go:Go-语言设计模式之建造者模式

前言你去买车,你不会只买一个轮胎、一个发动机、一个方向盘,你买的是一辆包含轮胎、方向盘、发动机、底盘、电气系统和车身等多个部件组成的残缺骑车。 在设计模式中,建造者模式就是解决如何将这些部件组装成一辆残缺的汽车并返回给用户的设计模式。建造者模式为客户端返回的不是一个简略的产品,而是一个由多个部件组成的简单产品。 思考如下问题假如让咱们思考如何创立一个屋宇对象。建造一栋简略的屋宇,你须要建造地板和四面的强,装置房门和窗户,而后再建造一个丑陋的屋顶。 但如果想要一个更宽敞舒服的别墅,还须要有院子、游泳池、动物和其余设施(例如中央空调、排水、供电设施),那又该怎么办呢? 最简略的办法就是扩大屋宇的积攒,而后创立一系列涵盖所有参数组合的子类。随着房子越简单,子类越多,任何新增的参数都会让这个层次结构更加简单。 另外一种形式则无需生成子类,咱们能够在屋宇基类中创立一个蕴含所有可能参数的超级构造函数,并用它来管制屋宇对象,这种办法的确能够防止生成子类,但它却会造成另外一个问题——结构函数参数太多。 House(windows, doors, rooms, hasSwimPool, hasGarden,...)但并不是所有的房子都须要游泳池,导致绝大部分的参数都没有应用,使得构造函数的申明简单,调用不整洁。 解决形式就是明天要介绍的建造者模式。 建造者模式概念建造者模式(Builder Pattern),又称生成器模式,是较为简单的创建者模式,它将客户端与蕴含多个组成部分的简单对象的创立过程拆散,客户端无需晓得简单对象的外部组成部分与拆卸形式,只须要晓得所需的建造者类型即可。 定义:将一个简单对象的构建与它的示意拆散,使得同样的构建过程能够创立不同的示意。 结构图如下: 由上图能够晓得,建造者模式蕴含 4 个角色: Builder 形象建造者:它为创立一个产品 Product 对象的各个部件指定形象接口,这个接口个别包含两类办法:buildPartX() :用于创立简单对象的各个部件getResult() :用于返回简单对象ConcreteBuilder 具体建造者:它实现了 Builder 接口,实现各个部件的具体结构和拆卸办法,定义并明确其所创立的简单对象,也能够提供一个办法返回创立好的简单产品对象Product 产品角色:它是最终被构建的简单对象,蕴含多个组成部件,具体建造者创立该产品的外部示意并定义其拆卸过程。Director 主管、指挥者:指挥者又被称为导演类,定义调用结构步骤的程序。它负责安顿负责对象的建造秩序,指挥者和形象建造者之间存在关联关系,能够在其 construct() 建造办法中调用建造者对象的部件结构与拆卸办法,实现负责对象的建造。Go 代码示例代码组织构造如下: 首先创立 house.go 文件, 建设 House 这个产品基类,代码如下;package maintype House struct { windowType string doorType string swimPool string floor int}正像前文所说一眼,房子有窗户、门、游泳池、楼层等局部组成。 而后创立形象创建者 iBuilder.go 文件,也是咱们的建造者接口,别离定义 4 个 set 和 1 个 getHouse() 办法,代码如下:package maintype IBuilder interface { setWindowType() setDoorType() setNumFloor() setSwimPool() getHouse() House}func getBuilder(builderType string) IBuilder { if builderType == "normal" { return newNormalBuilder() } if builderType == "cottages" { return newCottagesBuilder() } return nil}新建具体建造者:一般房子 normalBuilder.go,在这个文件中,因为 Go 语言没有继承的概念,所以也须要咱们定义跟 House 雷同的构造体,而后实现 normalHouse 的构建 :package maintype NormalBuilder struct { windowType string doorType string swimPool string floor int}func newNormalBuilder() *NormalBuilder { return &NormalBuilder{}}func (b *NormalBuilder) setWindowType() { b.windowType = "Wooden Window"}func (b *NormalBuilder) setDoorType() { b.doorType = "Wooden Door"}func (b *NormalBuilder) setNumFloor() { b.floor = 3}func (b *NormalBuilder) setSwimPool() { b.swimPool = "None"}func (b *NormalBuilder) getHouse() House { return House{ doorType: b.doorType, windowType: b.windowType, swimPool: b.swimPool, floor: b.floor, }}跟上一步同理,新建别墅具体建设者 cottagesBuilder.go 文件,代码如下:package maintype cottagesBuilder struct { windowType string doorType string swimPool string floor int}func newCottagesBuilder() *cottagesBuilder { return &cottagesBuilder{}}func (b *cottagesBuilder) setWindowType() { b.windowType = "Glass Window"}func (b *cottagesBuilder) setDoorType() { b.doorType = "Steel Security Door"}func (b *cottagesBuilder) setNumFloor() { b.floor = 1}func (b *cottagesBuilder) setSwimPool() { b.swimPool = "Swimming Pool"}func (b *cottagesBuilder) getHouse() House { return House{ doorType: b.doorType, windowType: b.windowType, swimPool: b.swimPool, floor: b.floor, }}新建主管 director.go ,主管构造体内也是形象建造者,其次主管有着 setBuilder() 和 buildHouse() 的职责,最初主管负责安顿负责对象的建造秩序,比方先确定门、窗、楼层,再思考是否须要加装泳池。最终代码如下:package maintype Director struct { builder IBuilder}func newDirector(b IBuilder) *Director { return &Director{ builder: b, }}func (d *Director) setBuilder(b IBuilder) { d.builder = b}func (d *Director) buildHouse() House { d.builder.setDoorType() d.builder.setWindowType() d.builder.setNumFloor() d.builder.setSwimPool() return d.builder.getHouse()}6.新建一个 main.go 文件,测试咱们的创建者模式是否正确: ...

April 3, 2023 · 2 min · jiezi

关于go:golang-中的cronjob

引言最近做了一个需要,是定时工作相干的。以前定时工作都是通过 linux crontab 去实现的,当初服务上云(tkex)了,尝试了 tkex 的 CronJob,因为公司提供的是界面化工具,应用、查看起来很不不便。于是有了本文,通过一个单 pod 去实现一个常驻服务,去跑定时工作。 通过筛选,选用了 cron 这个库,它反对 linux cronjob 语法取配置定时工作,还反对@every 10s、@hourly 等描述符去配置定时工作,齐全满足咱们要求,比方上面的例子: package mainimport ( "fmt" "github.com/natefinch/lumberjack" "github.com/robfig/cron/v3" "github.com/sirupsen/logrus")type CronLogger struct { clog *logrus.Logger}func (l *CronLogger) Info(msg string, keysAndValues ...interface{}) { l.clog.WithFields(logrus.Fields{ "data": keysAndValues, }).Info(msg)}func (l *CronLogger) Error(err error, msg string, keysAndValues ...interface{}) { l.clog.WithFields(logrus.Fields{ "msg": msg, "data": keysAndValues, }).Warn(err.Error())}func main() { logger := logrus.New() _logger := &lumberjack.Logger{ Filename: "./test.log", MaxSize: 50, MaxAge: 15, MaxBackups: 5, } logger.SetOutput(_logger) logger.SetFormatter(&logrus.JSONFormatter{ DisableHTMLEscape: true, }) c := cron.New(cron.WithLogger(&CronLogger{ clog: logger, })) c.AddFunc("*/5 * * * *", func() { fmt.Println("你的流量包行将过期了") }) c.AddFunc("*/2 * * * *", func() { fmt.Println("你的转码包行将过期了") }) c.Start() for { select {} }}应用了 cronjob、并联合了 golang 的 log 组建,输入日志到文件,应用很不便。 ...

April 2, 2023 · 2 min · jiezi

关于go:Go-语言数组和切片的区别

原文链接: Go 语言数组和切片的区别 在 Go 语言中,数组和切片看起来很像,但其实它们又有很多的不同之处,这篇文章就来说说它们到底有哪些不同。 另外,这个问题在面试中也常常会被问到,属于入门级题目,看过文章之后,置信你会有一个很好的答案。 数组数组是同一种数据类型元素的汇合,数组在定义时须要指定长度和元素类型。 例如:[4]int 示意一个蕴含四个整数的数组,数组的大小是固定的。并且长度是其类型的一部分([4]int 和 [5]int 是不同的、不兼容的类型)。 数组元素能够通过索引来拜访,比方表达式 s[n] 示意拜访第 n 个元素,索引从零开始。 申明以及初始化func main() { var nums [3]int // 申明并初始化为默认零值 var nums1 = [4]int{1, 2, 3, 4} // 申明同时初始化 var nums2 = [...]int{1, 2, 3, 4, 5} // ...能够示意前面初始化值的长度 fmt.Println(nums) // [0 0 0] fmt.Println(nums1) // [1 2 3 4] fmt.Println(nums2) // [1 2 3 4 5]}函数参数如果数组作为函数的参数,那么理论传递的是一份数组的拷贝,而不是数组的指针。这也就意味着,在函数中批改数组的元素是不会影响到原始数组的。 package mainimport ( "fmt")func Add(numbers [5]int) { for i := 0; i < len(numbers); i++ { numbers[i] = numbers[i] + 1 } fmt.Println("numbers in Add:", numbers) // [2 3 4 5 6]}func main() { // declare and initialize the array var numbers [5]int for i := 0; i < len(numbers); i++ { numbers[i] = i + 1 } Add(numbers) fmt.Println("numbers in main:", numbers) // [1 2 3 4 5]}切片数组的应用场景绝对无限,切片才更加罕用。 ...

April 2, 2023 · 2 min · jiezi

关于go:使用FFmpeg将视频转换成音频

整顿移动硬盘,发现了一段2017年,在西安回民街青旅,似曾相识的三人闲聊,过后为视频录制,时长近一小时40分钟,超过10G. 听了后感觉很有意思,但没必要应用视频,音频模式空间小,更适合. (三人别离为: 作为合伙人兼旅店日常理事的西南青年A,一表人才, 但其健谈水平远不迭另外两位; 在此无偿打工&收费住宿的与我个别大小的青年B,川陕之交的汉中宁强人,在海南读大学; 完结第一份工作, "无房车压力,有过万贷款"的C. 游历古都,攀登高岳, 便从汴州到杭州,开启了一段996生涯 后半段适逢在天津大学读研的俄罗斯西西伯利亚留学生问路华山,和其交谈些许) 苦于本地没有视频转音频工具,和共事闲聊时,说"不就是用FFmpeg一行命令的事吗",恍然大悟. 装置应用 brew install ffmpeg 时,因为依赖过多,(尤其降级Big Sur后),中途可能会报错: 这时仅需 brew install 装置失败的依赖名称, 而后再 brew install ffmpeg. 如此往返便可装置胜利. 将视频转换为音频ffmpeg -i 视频名.MOV -vn -acodec libmp3lame -ac 2 -qscale:a 4 -ar 48000 想要转成的音频名.mp3 不消几分钟,便可转换胜利 将音频切分成多段须要对音频资源进行裁剪,同样一行命令搞定: ffmpeg -i source.mp3 -vn -acodec copy -ss 00:00:00.00 -t 00:30:00 part1.mp3 -ss 从 小时:分:秒 处开始切割-t 持续时间-to 到 小时:分:秒.毫秒 处截止 将音频转为文字音频内容太长,想要转成文字. 目前有很多 提供在线音频转文字 性能的平台,但大多须要免费,或体验不佳. 多番比选尝试,发现 网易见外 综合下来最佳 ...

April 1, 2023 · 1 min · jiezi

关于go:Ristretto-简介-一个高性能-GO-缓存

这个博客登上了 Golang subreddit 的顶部,并且在 Hacker News 的 trending 上排在前十位。 肯定要在那里参加探讨,并通过给咱们一个 star,表白对咱们的喜爱。 通过六个月的研发,咱们骄傲的发表缓存 Ristretto:一个高性能、并发、可设置内存下限的 Go 缓存的初始版本。他是抗争用、扩展性好、提供稳固的高命中率。 前言这所有都始于 Dgraph 中须要一个可设置内存下限的、并发的 Go 缓存。咱们四处寻找解决方案,然而没有找到一个适合的。而后咱们尝试应用分片 map,通过分片驱赶来开释内存,这导致了咱们的内存问题。而后咱们从新利用了 Groupcache 的 LRU, 用互斥锁保障线程平安。应用了一年之后,咱们留神到缓存存在重大的争用问题。一个 commit 删除了该缓存,使咱们的查问提早显著改善了 5-10 倍。实质上,咱们的缓存正在减慢咱们的速度! 咱们得出的论断是,Go 中的并发缓存库曾经坏了,必须修复。 在三月, 咱们写了一篇对于 Go 中的缓存状态, 提到数据库和零碎须要一个智能的、可设置内存下限的缓存的问题,它能够扩大到 Go 程序所处的多线程环境。特地的,咱们将这些设置为缓存的要求: 并发的;缓存命中率高;Memory-bounded (限度为可配置的最大内存使用量);随着核数和协程数量的减少而扩大;在非随机key拜访(例如 Zipf)散布下很好的扩大;公布了博客文章之后,咱们组建了一个团队来解决其中提到的挑战,并创立了一个值得与非 Go 语言缓存实现进行比拟的 Go 缓存库。特地的,Caffeine 这是一个基于 Java 8 的高性能、近乎最优的缓存库。许多基于 Java 8 的数据库都在应用它, 比方 Cassandra,HBase,和 Neo4j。这里有一篇对于 Caffeine 设计的文章。 Ristretto: Better Half of Espresso从那以后咱们浏览了文献, 宽泛的测试了实现 ,并探讨了在写一个缓存库时须要思考的每一个变量。 明天,咱们骄傲的发表他曾经筹备好供更宽泛的 Go 社区应用和试验。 在咱们开始解说 Ristretto 的设计之前, 这有一个代码片段展现了如何应用它: ...

April 1, 2023 · 5 min · jiezi

关于go:基于GoGrpckubernetesIstio开发微服务的最佳实践尝试-33

基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 1/3 基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 2/3 基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 3/3 我的项目地址:https://github.com/janrs-io/Jgrpc 转载请注明起源: https://janrs.com/6rdh在前两局部中,咱们创立了两个微服务:pingservice 和 pongservice。 在这一部分中,咱们将创立用于主动部署的 CICD pipeline。 咱们假如您曾经部署了Jenkins/Gitlab/Harbor 和Kubenertes/Istio。 我的项目构造devops├── README.md├── ping│   └── dev│   ├── Deployment.yaml│   ├── Dockerfile│   ├── Jenkinsfile│   └── Service.yaml└── pong └── dev ├── Deployment.yaml ├── Dockerfile ├── Jenkinsfile └── Service.yaml4 directories, 9 files实际在 Jenkins 上,为每个微服务项目创立一个目录,而后在该目录下创立dev/test/prod流水线。 在 Gitlab 上,设置三个分支爱护分支:dev/test/prod。 这三个分支用于dev/test/production环境。这三个分支只能合并不能提交。 如果有新的微服务要开发,在 dev 分支的根底上新建一个分支,名称格局为:dev-*。 例如:dev-ping、dev-pong。而后为每个分支设置 webhook ,主动触发 Jenkins pipeline 主动部署到 kubernetes 集群。 微服务本地开发须要调试. 能够应用 kubefwd 工具或者kubernetes 官网举荐的 telepresence 。 ...

March 31, 2023 · 1 min · jiezi

关于go:基于GoGrpckubernetesIstio开发微服务的最佳实践尝试-23

基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 1/3 基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 2/3 基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 3/3 我的项目地址:https://github.com/janrs-io/Jgrpc 转载请注明起源:https://janrs.com/ugj7在上一部分中,咱们创立了微服务的目录构造并实现了微服务pongservice。 这部分咱们持续实现一个名为pingservice的微服务,拜访上一节曾经部署好的pongservice微服务。 创立一个新的微服务非常简单,只需复制之前创立的pongservice微服务,而后做一些小改变。 我的项目构造这部分最终的目录构造如下: pingservice├── buf.gen.yaml├── cmd│   ├── main.go│   └── server│   ├── grpc.go│   ├── http.go│   ├── run.go│   ├── wire.go│   └── wire_gen.go├── config│   ├── client.go│   ├── config.go│   └── config.yaml├── genproto│   └── v1│   ├── gw│   │   └── pingservice.pb.gw.go│   ├── pingservice.pb.go│   └── pingservice_grpc.pb.go├── go.mod├── go.sum├── proto│   ├── buf.lock│   ├── buf.yaml│   └── v1│   ├── pingservice.proto│   └── pingservice.yaml└── service ├── client.go └── server.go9 directories, 21 files开始复制在 src 目录下执行如下复制命令: ...

March 31, 2023 · 4 min · jiezi

关于go:基于GoGrpckubernetesIstio开发微服务的最佳实践尝试-13

基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 1/3 基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 2/3 基于Go/Grpc/kubernetes/Istio开发微服务的最佳实际尝试 - 3/3 我的项目地址:https://github.com/janrs-io/Jgrpc 转载请注明起源:https://janrs.com/br6fJgrpc本我的项目为基于 Go/Grpc/kubernetes/Istio 开发微服务的最佳实际提供参考。 并基于 Jenkins/Gitlab/Harbor 实现了CICD。 并应用 grpc-gateway 作为网关代理。 本最佳实际分为三个局部: 创立一个 pingservice 的微服务创立一个 pongservice 的微服务基于Jenkins/Gitlab/Harbor 创立 CICD 部署流程并部署到 k8s/istio在这一部分中,咱们将创立 pongservice 微服务。 前提假如曾经装置了以下工具: protoc-gen-grpc-gatewayprotoc-gen-openapiv2protoc-gen-goprotoc-gen-go-grpcbufwire上面是装置这些工具的教程地址: protoc-gen-grpc-gateway & protoc-gen-openapiv2 & protoc-gen-go & protoc-gen-go-grpc这四个工具的装置教程请查看:install protoc-gen* tools wirewire 工具的装置教程请查看:install wire tool bufbuf 工具的装置教程请查看:install buf tool 我的项目构造这部分最终的目录构造如下: Jgrpc├── devops├── istio-manifests├── kubernetes-manifests└── src └── pongservice ├── buf.gen.yaml ├── cmd │   ├── main.go │   └── server │   ├── grpc.go │   ├── http.go │   ├── run.go │   ├── wire.go │   └── wire_gen.go ├── config │   ├── config.go │   └── config.yaml ├── genproto │   └── v1 │   ├── gw │   │   └── pongservice.pb.gw.go │   ├── pongservice.pb.go │   └── pongservice_grpc.pb.go ├── go.mod ├── go.sum ├── proto │   ├── buf.lock │   ├── buf.yaml │   └── v1 │   ├── pongservice.proto │   └── pongservice.yaml └── service ├── client.go └── server.go14 directories, 20 files开始创立我的项目的整体目录构造如下: ...

March 31, 2023 · 5 min · jiezi

关于go:校验IP

代码如下(main.go): package mainimport ( "flag" "fmt" "net" "strings")const IPV4 = 4const IPV6 = 6func getIPType(ip string) int { for i := 0; i < len(ip); i++ { switch ip[i] { case '.': return IPV4 case ':': return IPV6 } } return 0}func main() { // Define flags macPtr := flag.String("mac", "", "MAC address") sipPtr := flag.String("sip", "", "Source IP address") dipPtr := flag.String("dip", "", "Destination IP address") vlanidPtr := flag.Int("vlanid", -1, "VLAN ID") intfNamePtr := flag.String("intf_name", "", "Interface name") // Parse flags flag.Parse() // Check if all flags are provided if *macPtr == "" || *sipPtr == "" || *dipPtr == "" || *vlanidPtr == 0 || *intfNamePtr == "" { fmt.Println("Usage: go run check.go -mac <mac> -sip <sip> -dip <dip> -vlanid <vlanid> -intf_name <intf_name>") return } // Check if the VLAN ID is valid if *vlanidPtr < 1 || *vlanidPtr > 4095 { fmt.Println("Invalid VLAN ID") return } // Check if the interface name is valid if len(*intfNamePtr) > 100 { fmt.Println("Interface name is too long") return } // Parse the MAC address mac, err := net.ParseMAC(*macPtr) if err != nil { fmt.Println("Invalid MAC address") return } // Check if the source IP address and destination IP address are of the same type if getIPType(*sipPtr) != getIPType(*dipPtr) { fmt.Println("Both source and destination IP addresses must be of the same type IPv4/IPv6") return } // Parse the source IP address sip := net.ParseIP(*sipPtr) if sip == nil { fmt.Println("Invalid source IP address") return } // Parse the destination IP address dip := net.ParseIP(*dipPtr) if dip == nil { fmt.Println("Invalid destination IP address") return } //Print the validated arguments fmt.Printf("MAC address: %s\n", mac) fmt.Printf("Source IP address: %s\n", sip) fmt.Printf("Destination IP address: %s\n", dip) fmt.Printf("VLAN ID: %d\n", *vlanidPtr) fmt.Printf("Interface name: %s\n", strings.TrimSpace(*intfNamePtr))}编译:go build -o check main.go ...

March 31, 2023 · 2 min · jiezi

关于go:高频必考DockerK8S面试题和答案

先送福利:Go如何主动解压缩包?| 文末送书 Docker如何在Docker容器外部拜访主机上的服务?能够通过设置主机网络模式,应用--net=host参数来拜访主机上的服务。这样,容器和主机将共享一个网络命名空间,容器将能够间接拜访主机上的服务。 如何在Docker容器中运行多个过程?Docker举荐每个容器只运行一个过程。如果须要在容器中运行多个过程,能够应用supervisord等过程管理工具来治理多个过程。 如何在Docker容器中应用环境变量?能够通过在Dockerfile中应用ENV指令定义环境变量,或者应用docker run命令的-e选项来设置环境变量。在容器外部,能够应用$ENV_NAME的形式来援用环境变量。 如何在Docker容器中共享数据?能够应用Docker数据卷来共享数据。数据卷是一个能够被容器内外拜访的非凡目录,能够在docker run命令中应用-v选项来创立和挂载数据卷。 如何在Docker容器中装置和应用ssh服务?能够在Dockerfile中装置openssh-server,而后启动sshd服务。同时,须要在docker run命令中应用-p选项将容器外部的22端口映射到主机上的一个端口,以便能够通过ssh连贯到容器。 如何在Docker容器中应用多个镜像?能够应用Docker Compose来组合多个镜像。在Docker Compose配置文件中,能够定义多个服务,每个服务对应一个镜像,而后应用docker-compose up命令来启动多个容器。 如何在Docker容器中运行GUI利用?能够在Dockerfile中装置图形界面相干的软件包,而后应用docker run命令的--env DISPLAY选项来设置显示环境变量,再应用--volume选项将主机上的X11套接字文件挂载到容器外部。这样,就能够在容器中运行GUI利用了。 如何在Docker容器中限度CPU和内存应用?能够应用docker run命令的--cpu-shares和--memory选项来限度CPU和内存应用。--cpu-shares选项能够设置CPU工夫片的权重,--memory选项能够设置容器可能应用的内存大小。 如何在Docker容器中设置时区?能够在Dockerfile中装置tzdata软件包,而后应用docker run命令的-e选项设置TZ环境变量为所需时区,或者应用--volume选项将主机上的/etc/localtime文件挂载到容器外部的相应地位。 如何在Docker容器中实现容器间通信?能够应用Docker网络来实现容器间通信。Docker提供了多种网络模式,如默认的bridge网络、host网络、overlay网络等。能够应用docker network命令来创立和管理网络,并应用--network选项指定容器所属的网络。在同一个网络中的容器能够间接通过容器名或IP地址互相拜访。 kubernetes什么是Kubernetes?Kubernetes是一个用于主动部署、扩大和治理容器化应用程序的开源平台。它提供了一个可扩大的、高可用的集群,并蕴含了自动化部署、负载平衡、存储管理、自我修复、主动扩容等性能。 Kubernetes中的Pod是什么?Pod是Kubernetes中最小的部署单元,它蕴含一个或多个严密耦合的容器和共享的存储/网络资源。Pod提供了一种形象层,使得容器能够在同一个主机上共享文件系统、网络命名空间等资源。 Kubernetes中的ReplicaSet是什么?ReplicaSet是一个用于治理Pod正本数量的控制器。它能够依据用户定义的正本数量,主动调整Pod的数量,以保障应用程序的高可用性。 Kubernetes中的Service是什么?Service是Kubernetes中一个形象的逻辑概念,用于裸露Pod的网络服务。Service能够将Pod的IP地址和端口映射到一个虚构的IP地址和端口上,从而实现了Pod的负载平衡和服务发现性能。 Kubernetes中的Deployment是什么?Deployment是一个用于治理Pod部署的控制器。它能够主动创立和更新Pod,以便放弃应用程序的可用性和可伸缩性。 Kubernetes中的ConfigMap和Secret是什么?ConfigMap是一个用于存储应用程序配置信息的对象,能够通过环境变量、命令行参数等形式应用。Secret是一个用于存储敏感信息(如明码、密钥等)的对象,能够加密存储。 Kubernetes中的DaemonSet是什么?DaemonSet是一个用于在每个节点上运行一个Pod的控制器。它能够用于运行一些须要在每个节点上运行的零碎级别的服务,如日志收集、监控等。 Kubernetes中的StatefulSet是什么?StatefulSet是一个用于治理有状态应用程序的控制器。它能够保障Pod的唯一性和有序性,从而实现有状态应用程序的可靠性。 Kubernetes中的HorizontalPodAutoscaler是什么?HorizontalPodAutoscaler是一个用于主动扩大Pod数量的控制器。它能够依据应用程序的负载状况,主动调整Pod数量,以保障应用程序的性能和可用性。 Kubernetes中的CSI是什么?CSI(Container Storage Interface)是一个用于存储管理的标准接口,它能够让存储提供商为Kubernetes提供自定义的存储解决方案。CSI能够让Kubernetes与不同的存储提供商进行集成,从而实现高度可定制化的存储管理。 一起学习欢送大家关注我,点赞、留言、转发。 你的反对,是我更文的最大能源!

March 31, 2023 · 1 min · jiezi

关于go:使用-Go-消费某里云-RocketMQ-中的消息

需要背景因为 Go-Cannal 常常挂掉,导致 MySQL binlog 同步到 ES 的链路故障。所以改用了另外一种同步计划。用某云的 DTS 生产 MySQL 的 binlong,用 DTS 的 Java 客户端生产 kafka 协定的音讯,失去 MySQL 的变更。Java 再将变更 Push 到 RocketMQ。革新原有的 Go 代码,生产 RocketMQ 音讯,实现业务逻辑( 复用之前的逻辑代码,减小开发量 )。 新计划采纳 MQ 长久化防止消费者 panic 导致数据失落,同时消费者能够分布式解决音讯进步吞吐率。 问题Go-SDK 的官网文档 : https://help.aliyun.com/document_detail/141783.html?spm=5176.... 坑一,RocketMQ 的服务不能用 apache RocketMQ 的 Go client。必须应用官网的 sdk,且官网 sdk 只有 http 协定版本。 坑二,官网的 SDK 中的 token 字段并无用处,能够为空或者任意字符 坑三,官网的 SDK 中 GetConsumer(InstanceID, Topic, Consumer, "*") 第三个参数其实是 TopicName ,或者必须写成 TopicName 一样的值。 ...

March 30, 2023 · 1 min · jiezi

关于go:milvus-中的-Indexcoord-Datacoord-和-Querycoord-都是些啥

在 Milvus 中,IndexCoord、DataCoord和QueryCoord是三个要害组件,它们别离负责解决索引、数据和查问。 IndexCoord: 负责管理索引。当数据插入 Milvus 时,IndexCoord会查看是否须要创立新的索引。在查问数据时,IndexCoord会确定应用哪些索引以进步查问效率。DataCoord: 负责管理数据。DataCoord负责解决数据的写入、读取和删除申请,并将数据调配到正确的分片中。当一个分片中的数据达到肯定大小时,DataCoord会创立一个新的分片。QueryCoord: 负责管理查问。QueryCoord接管查问申请并将其转发到正确的分片。它还负责将查问的后果合并并返回给客户端。Milvus应用这种分布式的架构来解决大规模向量数据。这使得Milvus可能疾速高效地解决海量向量数据,并提供实时、精确的查问后果。 参考: milvus 架构

March 30, 2023 · 1 min · jiezi

关于go:gin中Context中的GetQueryParam函数都是从哪里获取数据的

大家好,我是渔夫子。 在应用gin框架解决一次申请的过程中,能够通过Context构造体提供的办法获取或设置一个指定key的值。在Context中有多个通过key获取值的函数:GetString(key string) (s string)、Param(key string) string、Query(key string) (value string)、PostForm(key string) (value string)、GetHeader(key string)、Cookie(name string)等。 那么,这些函数到底是从哪里获取数据的呢?本文就带你一起来探索这些函数底层的数据源。 Context中Get函数的数据源Context.Get函数是从Context.Keys字段中获取的数据。咱们看下Context的Keys字段的定义(为不便文章阐明,咱们省略了Context中的其余无关字段): type Context struct { // Keys is a key/value pair exclusively for the context of each request. Keys map[string]any}能够看到,Keys是一个map[string]any类型的map。any是gin中interface{}的别名。通过该定义可知,在Keys字段中键必须是string类型,值能够是任意类型。 这个Keys中的值又来源于哪里呢?是在gin服务在解决申请时通过Context.Set函数设置的。Keys里的数据的生命周期是本次申请,作用域范畴也仅限于本次申请。申请完结了,Keys里的值也就完结了。 同时,Context.Keys字段的初始化也采纳了lazy模式。即在应用Context.Set函数时才进行初始化的。 对于Get函数来说,还有一些GetXXX的辅助函数,比方:MustGet、GetString、GetBool、GetInt、GetInt64等等,也都是从Keys中获取数据。 Context中Param函数的Context.Param(key string)函数是从正则门路中获取对应的匹配数据值。在gin中,正则门路的参数是被解析到Context.Params字段中的。其字段定义如下: type Context struct { Params Params}type Params []Paramtype Param struct { Key string Value string}例如,咱们定义了正则门路 "/user/:id",那么通过c.Param("id")函数就能获取到本次路由中的id参数值。 router.GET("/user/:id", func(c *gin.Context) { // a GET request to /user/john id := c.Param("id") // id == "john"})Context中Query函数的数据源Context.Query函数是获取的url中的查问参数的值。在gin中,将查问参数的值会解析到Context中的queryCache字段中,而queryCache的数据则来源于Context.Request.URL.RawQuery中。如下: ...

March 29, 2023 · 1 min · jiezi

关于go:limit与分页键

博客:cbb777.fun 全平台账号:安妮的心动录 github: https://github.com/anneheartrecord 下文中我说的可能对,也可能不对,鉴于笔者程度无限,请君自辨。有问题欢送大家找我探讨~ limit与分页在SQL中,limit用于限度返回的后果行数。LIMIT语句能够用于SELECT查问,用于限度查问后果集的行数,从而在解决大型数据集时,缩小数据库的负载,进步查问的性能 根本语法如下 SELECT * FROM table_name LIMIT [offset],row_count;//table_name是表名//offset是可选的偏移量,用于指定要从构造集的哪个地位开始返回行如果省略该参数,默认从第一行开始返回//row_count一共返回的行数,也就是查问失去的数量比方select * from students limit 5,10;或者select * from students limit 10 offset 5;limit在理论利用中常用于分页查问 举个例子 当初我有一个article表,想要做到文章分页展现的性能,每一页展现10篇文章 //表构造如下CREATE TABLE article (id int(11) not null auto_increment,title varchar(255) not null,content text,publish_time datetime not null,primary key (id));/这个时候调用方传来一个n,通常是Logic层往dao层传 伪代码如下select * from article order bypublish_time desc limit ?,10 values (n*10);//这条SQL就能做到文章分页的性能,依照工夫来分页//具体实际中可能没有这么简略,通常是热度、工夫等等深分页查问后果集中的某个地位之后的记录,即查问后果集的偏移量很大的状况。这样须要扫描的数据量就很大,可能导致查问的性能变得很低下 如何防止深分页的问题 应用更小的偏移量:比方将偏移量从10000升高到100应用分页键缓存后果集,在内存层面进行返回分库分表,缩小每个表的数据量大小分页键分页键(pagination key)是一种用于分页查问的技术,它能够帮忙咱们在大数据汇合中疾速定位到须要查问的数据段。分页键通常是一个惟一的标识符,能够示意查问后果集中的某一行。在应用分页键的时候,通过查问分页键来定位后果集的起始地位,从而防止了偏移量很大的状况,也就是防止了SQL深分页的状况。 举个例子,假如咱们须要查问一个蕴含一百万行数据的用户表,并且咱们须要查问第500001到第500100行的数据。如果用偏移量的形式进行查问,须要查问前5000000行数据能力取得咱们须要的后果,这将导致查问性能十分低下。而应用分页键的形式,能够在查问时间接指定分页键的值,从而定位到后果集的起始地位,防止了大量的数据扫描。 应用分页键的时候,咱们须要抉择一个适合的字段作为分页键,并确保该字段具备唯一性。通常状况下,自增长主键或者工夫戳字段都是比拟好的抉择,分页键实用于有序数据集的分页查问 上面有一个具体的栗子 假如咱们有一个蕴含大量文章的表,每篇文章都有一个惟一编号id和公布工夫publish_time两个字段。咱们须要查问公布工夫在2022年1月1日到2022年3月31日之间的文章,并依照公布工夫进行排序,每页显示十篇文章,显示第六页的数据 1.抉择分页键:依据查问条件,咱们抉择publish_time作为分页键2.查问第五页的最初一篇文章的公布工夫咱们得确定第五页最初一篇文章的公布工夫select publish from articles where publish_time>='2022-01-01 00:00:00'and publish_time<='2022-03-31 23:59:59'order by pulish_time asc limit 1 offset 50;3.应用分页键查问数据select * FROM articels where publish_time>='分页键的值'and publish_time<='2022-03-31 23:59:59'order by publish_time asc limit 10;

March 29, 2023 · 1 min · jiezi

关于go:GoEasyUtils-一个轻量级的基本数据类型处理库可以像php的array那样优雅的处理切片等服务

Go Easy Utils 是一个为 Go 开发者设计的工具库,旨在为开发者提供简略易用的工具函数和罕用操作。该库领有丰盛的函数,可帮忙您轻松实现各种常见的编程工作。 Go Easy Utils 的代码简略、易于浏览和保护。这个库遵循 Go 的最佳实际,代码正文具体,函数名和参数清晰易懂,方便使用和二次开发。此外,Go Easy Utils 的代码品质也失去了宽泛的认可,并失去了社区的大力支持和奉献。 该工具库蕴含了多种实用函数,如字符串解决、文件操作、日期工夫解决、加密解密、数组切片、网络申请等,能够大大提高开发效率。您能够应用这些函数来疾速开发出高效牢靠的应用程序。 Go Easy Utils 还反对 Go Modules,这使得您能够轻松地将该库与其余依赖项一起应用。此外,咱们致力于在 Go 的最新版本中对该库进行测试和优化,确保它在不同的操作系统战争台上都能失常运行。 如果您正在寻找一个高质量、易用、易扩大的 Go 工具库,那么 Go Easy Utils 相对是一个不错的抉择。咱们十分欢迎您退出咱们的社区,与咱们一起为 Go 的开发者们提供更好的工具和服务。 仓库地址:https://github.com/jefferyjob/go-easy-utils

March 29, 2023 · 1 min · jiezi

关于go:Golang-版的-PSR3-Logger-规范支持自定义-Logger

开源地址https://github.com/go-packagist/loggerhttps://flc.io/go-packagist-logger/阐明: 设计参考 PHP PSR-3 标准,做了一些调整后实现。装置go get github.com/go-packagist/logger教程package mainimport ( "fmt" "github.com/go-packagist/logger" "time")type CustomLogger struct { logger.Loggerable}var _ logger.Logger = (*CustomLogger)(nil)func NewCustomLogger() *CustomLogger { c := &CustomLogger{ Loggerable: func(level logger.Level, s string) { fmt.Println(fmt.Sprintf("%s %s: %s", time.Now().Format(time.DateTime), level.UpperString(), s)) }, } return c}func main() { c := NewCustomLogger() c.Emergencyf("Emergencyf: %s", "test") c.Alertf("Alertf: %s", "test") c.Criticalf("Criticalf: %s", "test") c.Errorf("Errorf: %s", "test") c.Warningf("Warningf: %s", "test") c.Noticef("Noticef: %s", "test") c.Infof("Infof: %s", "test") c.Debugf("Debugf: %s", "test") c.Emergency("Emergency: test") c.Alert("Alert: test") c.Critical("Critical: test") c.Error("Error: test") c.Warning("Warning: test") c.Notice("Notice: test") c.Info("Info: test") c.Debug("Debug: test") c.Log(logger.Emergency, "Log: Emergency: test") // Output: // 2023-03-28 23:18:13 EMERGENCY: Emergencyf: test // 2023-03-28 23:18:13 ALERT: Alertf: test // 2023-03-28 23:18:13 CRITICAL: Criticalf: test // 2023-03-28 23:18:13 ERROR: Errorf: test // 2023-03-28 23:18:13 WARNING: Warningf: test // 2023-03-28 23:18:13 NOTICE: Noticef: test // 2023-03-28 23:18:13 INFO: Infof: test // 2023-03-28 23:18:13 DEBUG: Debugf: test // 2023-03-28 23:18:13 EMERGENCY: Emergency: test // 2023-03-28 23:18:13 ALERT: Alert: test // 2023-03-28 23:18:13 CRITICAL: Critical: test // 2023-03-28 23:18:13 ERROR: Error: test // 2023-03-28 23:18:13 WARNING: Warning: test // 2023-03-28 23:18:13 NOTICE: Notice: test // 2023-03-28 23:18:13 INFO: Info: test // 2023-03-28 23:18:13 DEBUG: Debug: test // 2023-03-28 23:18:13 EMERGENCY: Log: Emergency: test}内置 Loggerlogger.NewNullLogger() - 啥也不干logger.NewPrintLogger() - 打印到控制台参考资料PSR-3: Logger Interface:https://www.php-fig.org/psr/psr-3/PSR Log:https://github.com/php-fig/logGo Redis: https://github.com/redis/go-redis/ (参考了一些设计思路)

March 29, 2023 · 1 min · jiezi

关于go:提速-30-倍OCI-容器启动优化的历程

文本翻译自: https://www.scrivano.org/posts/2022-10-21-the-journey-to-spee... 原文作者是 Red Hat 工程师 Giuseppe Scrivano ,其回顾了将 OCI 容器启动的工夫提速 30 倍的历程。当我开始钻研 crun (https://github.com/containers/crun) 时,我正在寻找一种通过改良 OCI 运行时来更快地启动和进行容器的办法,OCI 运行时是 OCI 堆栈中负责最终与内核交互并设置容器所在环境的组件。 OCI 运行时的运行工夫十分无限,它的工作次要是执行一系列间接映射到 OCI 配置文件的零碎调用。 我很诧异地发现,如此琐碎的工作可能须要破费这么长时间。 免责申明:对于我的测试,我应用了 Fedora 装置中可用的默认内核以及所有库。除了这篇博文中形容的修复之外,这些年来可能还有其余可能影响整体性能的修复。 以下所有用于测试的 crun 版本都是雷同的。 对于所有测试,我都应用 hyperfine,它是通过 cargo 装置的。 2017年的状况如何要比照咱们与过来相差多大,咱们须要回到 2017 年,或者只装置一个旧的 Fedora 映像。对于上面的测试,我应用了基于 Linux 内核 4.5.5 的 Fedora 24。 在新装置的 Fedora 24 上,运行从主分支构建: # hyperfine 'crun run foo'Benchmark 1: 'crun run foo' Time (mean ± ): 159.2 ms ± 21.8 ms [User: 43.0 ms, System: 16.3 ms] Range (min … max): 73.9 ms … 194.9 ms 39 runs用户工夫和零碎工夫指的是过程别离在用户态和内核态的耗时。160 毫秒很多,据我所知,这与我五年前察看到的状况类似。 ...

March 28, 2023 · 7 min · jiezi

关于go:Go语言中的接口类型interface

接口接口是用来定义行为的类型,定义的行为不禁接口间接实现,而由通过办法由定义的类型实现 Golang中,接口是一组办法的签名,是语言中一个重要的组成部分,其目标是通过引入一个中间层与具体的实现进行拆散,达到解耦合的作用,同时暗藏底层实现,缩小关注点 Golang不同于Java,通过隐式实现申明的接口,即只有实现了接口申明中的办法,就是实现了接口,接口的定义须要应用interface关键字,且在接口中只能定义方法签名,不能蕴含成员变量 基于官网的io包进行剖析: type Reader interface { Read(p []byte) (n int, err error)}下面是io包中申明的Reader接口,如果一个类型须要实现Reader接口,那么就仅须要实现Read(p []byte) (n int, err error)办法,如LimitedReader就实现了Reader接口: type LimitedReader struct { R Reader N int64}func(l *LimitedReader) Read(p []byte) (n int, err error) { if ;.N <= 0 { return 0, EOF } if int64(len(p)) > l.N { p = p[o:l.N] } n, err := l.R.Read(p) l.N -= int64(n) return}Golang只会在参数传递、返回参数和变量赋值时对类型是否实现了某个接口进行查看,接口在定义方法时对实现的接受者做限度,所以会有两种形式实现接口:构造体实现和指针实现。但这两种实现形式不能够同时存在,Go语言的编译器会在构造体类型和指针类型都实现同一个办法时报错“method redeclared” type Cat struct {}type Duck interface {}func (c Cat) Quack {} // 构造体实现func (c *Cat) Quack {} // 指针实现var d Duck = Cat{} // 构造体初始化var d Duck = &Cat{} // 指针初始化留神:指针实现接口,构造体初始化变量是无奈通过编译的;而构造体实现接口,指针初始化变量能够(Golang在传递参数是值传递的,指针初始化变量时,指针能够隐式地获取到指向的构造体:c.i能够了解成(*c).i)具体了解就是在Golang中,初始化变量后进行办法调用时会产生`值拷贝`:1.对于初始化的指针来说,意味着拷贝的新指针依然与原指针一样,指向一个雷同且惟一的构造体,所以编译器能够隐式通过对变量的解援用(dereference)获取到指针的构造体2.而对于构造体而言,这是拷贝生成了新的构造体,但办法的参数是指针,编译器既不可能创立一个新的指针,即便创立也无奈指向最后调用该办法的构造体具体的例子如Goinaction的代码示例:listing36.gopackage mainimport ( "fmt")type notifier interface { notify()}type user struct { name string email string}func (u *user) notify() { fmt.Printf("Sending user email to %s<%s>)\n", u.name, u.email)}func main() { u := user{"Bill", "bill@email.com"} sendNotification(u)}func sendNotification(n notifier) { n.notify()}认真查看代码就会发现u是一个构造体类型,而notify办法是应用指针接受者实现的,上述代码天然就无奈编译通过数据结构Golang依据接口类型是否蕴含一组办法将接口类型分成两类: ...

March 28, 2023 · 1 min · jiezi

关于go:MongoDB-这一篇就够了

MongoDBMongoDB是一个基于分布式文件存储的数据库,MongoDB是一个介于关系数据库和非关系数据库(nosql)之间的数据库产品。 MongoDB与MySQL术语比照MongoDBMySQLdatabasedatabasecolumnfielddocumentrowcollectiontabledatabase 数据库,与SQL的数据库(database)概念雷同,一个数据库蕴含多个汇合(表)collection汇合,相当于SQL中的表(table),一个汇合能够寄存多个文档(行)。不同之处就在于汇合的构造(schema)是动静的,不须要事后申明一个严格的表构造。更重要的是,默认状况下 MongoDB并不会对写入的数据做任何schema的校验; document 文档,相当于SQL中的行(row),一个文档由多个字段(列)组成,并采纳bson(json)格局示意;field字段,相当于SQL中的列(column),相比一般column的差异在于field的类型能够更加灵便,比方反对嵌套的文档、数组;MongoDB vs. 关系型数据库 实用场景利用不须要事务及简单 join 反对新利用,需要会变,数据模型无奈确定,想疾速迭代开发利用须要2000-3000以上的读写QPS(更高也能够)利用须要TB甚至 PB 级别数据存储利用倒退迅速,须要能疾速程度扩大利用要求存储的数据不失落 利用须要99.999%高可用利用须要大量的地理位置查问、文本查问存储引擎和索引存储引擎WiredTiger存储引擎之一:根底数据结构剖析 索引类型MongoDB 索引详解(一) 事物始终以来,"不反对事务" 是 MongoDB 始终被诟病的问题,当然也能够说这是 NoSQL 数据库的一种衡量(放弃事务,谋求高性能、高可扩大),但本质上,MongoDB 很早就有事务的概念,然而这个事务只能是针对单文档的,即单个文档的操作是有原子性保障的。在4.0 版本之后,MongoDB 开始反对多文档的事务: 4.0 版本反对正本集范畴的多文档事务;4.2 版本反对跨分片的多文档事务(基于两阶段提交);MongoDB 尽管曾经在 4.2 开始全面反对了多文档事务,但并不代表大家应该毫无节制地应用它。相同,对事务的应用准则应该是:能不必尽量不必。通过正当地设计文档模型,能够躲避绝大部分应用事务的必要性 为什么?事务 = 锁,节点协调,额定开销,性能影响MongoDB WiredTiger存储引擎反对read-uncommitted、read-committed和snapshot3种事务隔离级别,MongoDB启动时默认抉择snapshot隔离。 隔离级别形容read-uncommitted一个事务的批改,即便没有提交,对其余事务也都是可见的。事务能够读取未提交的数据,这也被称为“脏读(dirty read)”read-committed一个事务从开始直到提交之前,所做的任何批改对其余事务都是不可见的snapshot事务开始时,零碎会创立一个快照,从已提交的事务中获取行版本数据,如果行版本数据标识的事务尚未提交,则从更早的事务中获取已提交的行版本数据作为其事务开始时的值。相似于 Repeatable Read事务开发:写操作事务writeConcern:决定一个写操作落到多少个节点上才算胜利。writeConcern 的取值包含: 0:发动写操作,不关怀是否胜利;1~集群最大数据节点数:写操作须要被复制到指定节点数才算胜利;majority:写操作须要被复制到大多数节点上才算胜利。all:写操作须要被复制到全副节点上才算胜利。事务开发:读操作事务在读取数据的过程中咱们须要关注以下两个问题: 从哪里读?什么样的数据能够读?第一个问题是是由 readPreference:决定应用哪一个节点来满足正在发动的读申请 primary: 只抉择主节点;primaryPreferred:优先选择主节点,如果不可用则抉择从节点;secondary:只抉择从节点;secondaryPreferred:优先选择从节点,如果从节点不可用则抉择主节点;nearest:抉择最近的节点;第二个问题则是由 readConcern:决定这个节点上的数据哪些是可读的,相似于关系数据库的隔离级别 available:读取所有可用的数据;local:读取所有可用且属于以后分片的数据;majority:读取在大多数节点上提交实现的数据;linearizable:可线性化读取文档;snapshot:读取最近快照中的数据;事务开发:多文档事务MongoDB ACID事务反对 高可用复制集机制及原理MongoDB的 复制集相似于MySQL的主从架构,然而又比MySQL的主从架构要弱小的多。复制集的作用: 数据写入时将数据迅速复制到另一个独立节点上在承受写入的节点产生故障时主动选举出一个新的代替节点在实现高可用的同时,复制集实现了其余几个附加作用: 数据散发:将数据从一个区域复制到另一个区域,缩小另一个区域的读提早读写拆散:不同类型的压力别离在不同的节点上执行异地容灾:在数据中心故障时候疾速切换到异地复制集架构 一个典型的复制集由3个以上具备投票权的节点组成,包含:一个主节点(PRIMARY):承受写入操作和选举时投票两个(或多个)从节点(SECONDARY):复制主节点上的新数据和选举时投票不举荐应用 Arbiter(投票节点)数据是如何复制的 当一个批改操作,无论是插入、更新或删除,达到主节点时,它对数据的操作将被记录下来(通过一些必要的转换),这些记录称为 oplog。从节点通过在主节点上关上一个 tailable 游标一直获取新进入主节点的 oplog,并在本人的数据上回放,以此放弃跟主节点的数据统一。 分片集群架构 路由节点 mongos:提供集群入口、转发利用端申请、抉择适合数据节点进行读写、合并多个数据节点的返回配置节点 Config:提供集群元数据存储、分片数据分布的映射数据节点 mongod:负责存储数据库数据,每个Shard数据分片默认三节点正本集(三节点正本集由Primary节点+1个Secondary节点+1个Arbiter节点形成)、以复制集为单位横向扩大分片集群特点:利用全透明,无非凡解决、数据主动平衡、动静扩容,毋庸下线 数据分片策略 Chunks块:MongoDB将分片数据拆分成块。每个分块都有一个基于分片键的上上限范畴 基于范畴:范畴分片能很好的满足『范畴查问』的需要,比方想查问x的值在[-75, 25]之间的所有文档,这时mongos间接能将申请路由到Chunk2,就能查问出所有符合条件的文档。 长处:片键范畴查问性能好、优化读毛病:数据分布可能不平均、容易有热点基于 Hash:Hash分片是依据用户的shard key计算hash值(64bit整型),依据hash值依照『范畴分片』的策略将文档散布到不同的chunk ...

March 28, 2023 · 1 min · jiezi

关于go:Gvm安装的go在Vscode中无法识别并且无法安装Vscode的go环境

问题: Gvm装置的go在Vscode中无奈辨认并且无奈装置Vscode的go环境, 这个坑爬了好一会;解决办法: 1. gvm pkgenv 查问环境记住这两条:export GOROOT; GOROOT="$GVM_ROOT/..."export GOPATH; GOPATH="$GVM_ROOT/..."`2. vscode中设置搜寻go.goroot, 增加go.gopath对应填入上方查问到的门路,留神点: 应用绝对路径"go.goroot": "","go.gopath": "",`

March 28, 2023 · 1 min · jiezi

关于go:一分钟搞明白快速掌握-Go-WebAssembly

大家好,我是煎鱼。 最近因为各种奇怪的起因,更多的接触到了 WebAssembly。尽管之前很多博客也翻过写过各种文章,但总感觉欠些滋味。于是明天梳理了一版,和大家一起开展学习。 先来一张经典图: WebAssembly 是什么以下是 Mozilla 在 MDN 上给出的定义: WebAssembly(缩写:Wasm)是一种新的编码方式,能够在古代的网络浏览器中运行 - 它是一种低级的类汇编语言,具备紧凑的二进制格局,能够靠近原生的性能运行,并为诸如 C/C++ 等语言提供一个编译指标,以便它们能够在 Web 上运行。它也被设计为能够与 JavaScript 共存,容许两者一起工作。Wasm 官网本人挑出的重点是: 是一种基于堆栈的虚拟机的二进制指令格局。被设计为编程语言的可移植编译指标。可能在网络上部署客户端和服务器应用程序。新编码方式,能够在浏览器中运行。能够以靠近原生的性能运行。能够跨语言,例如:C/C++;能够与 JavaScript 共存。 看着是一个不错的可跨平台运行的新玩具。 由哪家研发最早 WebAssembly1.0 基于 asm.js(Javascript 的严格子集,动态类型,勾销垃圾回收机制等)的个性集实现。随后的 WebAssembly2.0 又依据新的规范进行了进一步的延长和开发。 WebAssembly 的开发团队别离来自 Mozilla、Google、Microsoft、Apple,代表着四大网络浏览器 Firefox、Chrome、Microsoft Edge、Safari。 一些重要的工夫线: 2015 年 WebAssembly 首次公布,在上述四大浏览器中进行了 Unity 的 Angry Bots(愤恨的机器人)的演示。2017 年 3 月,首次公布 WebAssembly MVP 版本,预览版本完结,正式进行公布,能够了解为 1.0。2018 年 2 月,WebAssembly 工作组(WebAssembly Working Group)公布了外围标准、JavaScript 接口和 Web API 的三个公开工作草案。2019 年,Chrome 75 公布,默认启用 WebAssembly 线程。2022 年 6 月,开始公布 WebAssembly 2.0。几家大厂派人一起做的,比拟新,近几年才开始更多的被反对。以后还在 WebAssembly 2.0 的阶段,还在倒退阶段。 ...

March 27, 2023 · 2 min · jiezi

关于go:写给go开发者的gRPC教程超时控制

本篇为【写给go开发者的gRPC教程系列】第六篇 第一篇:protobuf根底 第二篇:通信模式 第三篇:拦截器 第四篇:错误处理 第五篇:metadata 第六篇:超时管制 本系列将继续更新,欢送关注获取实时告诉 导言 一个正当的超时工夫是十分必要的,它能进步用户体验,进步服务器的整体性能,是服务治理的常见伎俩之一 为什么要设置超时用户体验:很多RPC都是由用户侧发动,如果申请不设置超时工夫或者超时工夫不合理,会导致用户始终处于白屏或者申请中的状态,影响用户的体验 资源利用:一个RPC会占用两端(服务端与客户端)端口、cpu、内存等一系列的资源,不合理的超时工夫会导致RPC占用的资源迟迟不能被开释,因此影响服务器稳定性 综上,一个正当的超时工夫是十分必要的。在一些要求更高的服务中,咱们还须要针对DNS解析、连贯建设,读、写等设置更精密的超时工夫。除了设置动态的超时工夫,依据以后零碎状态、服务链路等设置自适应的动静超时工夫也是服务治理中一个常见的计划。 客户端的超时连贯超时还记得咱们怎么在客户端创立连贯的么? conn, err := grpc.Dial("127.0.0.1:8009", grpc.WithInsecure(),)if err != nil { panic(err)}// c := pb.NewOrderManagementClient(conn)// // Add Order// order := pb.Order{// Id: "101",// Items: []string{"iPhone XS", "Mac Book Pro"},// Destination: "San Jose, CA",// Price: 2300.00,// }// res, err := c.AddOrder(context.Background(), &order)// if err != nil {// panic(err)// }如果指标地址127.0.0.1:8009无奈建设连贯,grpc.Dial()会返回谬误么?这里间接放论断:不会的,grpc默认会异步创立连贯,并不会阻塞在这里,如果连贯没有创立胜利会在上面的RPC调用中报错。 如果咱们想管制连贯创立时的超时工夫该怎么做呢? 异步转成同步:首先咱们须要应用grpc.WithBlock()这个选项让连贯的创立变为阻塞式的超时工夫:应用grpc.DialContext()以及Go中context.Context来管制超时工夫于是实现如下,当然应用context.WithDeadline()成果也是一样的。连贯如果在3s内没有创立胜利,则会返回context.DeadlineExceeded谬误 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)defer cancel()conn, err := grpc.DialContext(ctx, "127.0.0.1:8009", grpc.WithInsecure(), grpc.WithBlock(),)if err != nil { if err == context.DeadlineExceeded { panic(err) } panic(err)}服务调用的超时和下面连贯超时的配置相似。无论是一般RPC还是流式RPC,服务调用的第一个参数均是context.Context ...

March 27, 2023 · 2 min · jiezi

关于go:Golang-数据类型转换

string To int字符串为纯数字,值为:123456 aInt, _ := strconv.Atoi("123456")fmt.Printf("数据类型: %T, 值: %d", aInt, aInt) 字符串不为纯数字,值为:0 aInt, _ := strconv.Atoi("123456d")fmt.Printf("数据类型: %T, 值: %d", aInt, aInt) int To Stringint转到字符串 aInt := strconv.Itoa(1234)fmt.Printf("数据类型: %T, 值: %v", aInt, aInt) int64转字符串 int64取值范畴:-9223372036854775808 - 9223372036854775807 aInt := strconv.Itoa(1234)fmt.Printf("数据类型: %T, 值: %v", aInt, aInt)

March 26, 2023 · 1 min · jiezi

关于go:Go-语言-new-和-make-关键字的区别

原文链接: Go 语言 new 和 make 关键字的区别 本篇文章来介绍一道十分常见的面试题,到底有多常见呢?可能很多面试的开场白就是由此开始的。那就是 new 和 make 这两个内置函数的区别。 其实这个问题自身并不简单,简略来说就是,new 只分配内存,而 make 只能用于 slice、map 和 chan 的初始化,上面咱们就来具体介绍一下。 newnew 是一个内置函数,它会调配一段内存,并返回指向该内存的指针。 其函数签名如下: 源码// The new built-in function allocates memory. The first argument is a type,// not a value, and the value returned is a pointer to a newly// allocated zero value of that type.func new(Type) *Type从下面的代码能够看出,new 函数只承受一个参数,这个参数是一个类型,并且返回一个指向该类型内存地址的指针。 同时 new 函数会把调配的内存置为零,也就是类型的零值。 应用应用 new 函数为变量分配内存空间: p1 := new(int)fmt.Printf("p1 --> %#v \n ", p1) //(*int)(0xc42000e250) fmt.Printf("p1 point to --> %#v \n ", *p1) //0var p2 *inti := 0p2 = &ifmt.Printf("p2 --> %#v \n ", p2) //(*int)(0xc42000e278) fmt.Printf("p2 point to --> %#v \n ", *p2) //0下面的代码是等价的,new(int) 将调配的空间初始化为 int 的零值,也就是 0,并返回 int 的指针,这和间接申明指针并初始化的成果是雷同的。 ...

March 26, 2023 · 2 min · jiezi

关于go:LDAP-是个啥你知道吗

最近业务上须要和 LDAP 对接,在想 LDAP 是个啥? 连忙查查材料,补齐一下我的常识盲区 LDAP 是什么?LDAP 就是一个 轻量目录拜访协定, 全称是 (Lightweight Directory Access Protocol),是基于X.500规范的轻量级目录拜访协定 咱们就能够了解成,他就是一个目录数据库,读的性能超级高,写性能不如人意,所以咱们基本上都是查问它居多 LDAP 的产品有哪些?OpenLDAPMiscroSoft 的Active DirectoryIBM Security Directorysun 公司的 ldap其余的 ldap置信只有相熟了 LDAP 的根本协定,对接上述其余公司的产品应该都是信手拈来了 LDAP 必须晓得的基本概念?下面咱们晓得基于 LDAP 协定做进去的产品有很多,咱们以 Active Directory 为例 对立来看看 LDAP 咱们须要晓得哪些基本概念吧 Active Directory 见名知意,就是流动目录的意思 其中的重要概念有: DC Domain Controller就是域控制器,是十分外围的 其实他就是一台 AD 里的服务器,装置了流动目录的 PC 而已,所有域用户的信息都会存在这个 Domain Controller 外面,他就是整个流动目录的服务器 当你本地的 PC 装上 Active Directory 之后,那么就没有本地用户了,就会全副主动变成域用户 成员计算机跟域控制器建设了信赖并退出到域外面的计算机 , 每台计算机退出到域的时候会生成信赖密钥,相似于咱们服务端经常应用 token 一样 并且每隔一段时间,拜访其余成员的计算机是须要通过 Domain Controller 来拿到 token 来实现的,这样能力域计算机之间相互拜访 ...

March 26, 2023 · 1 min · jiezi

关于go:go-web-工程脚手架

go-web-quickstartgithub: https://github.com/fengjx/go-web-quickstartgitee: https://gitee.com/fengjx/go-web-quickstartgo web 工程示例,能够作为一些我的项目工程构造参考,对一些罕用性能做了简略封装。反对构建docker镜像。 示例中已实现了局部性能实现,不便做一些参考 用户登录、注册博客查看、增加、删除、批改环境依赖MySQL 初始化sql在deployments/dbRedis对应配置在configs目录,能够自行批改 make 指令$ make helpMakefile cmd: build: 我的项目打包 build-go: 构建 golang 包 fmt-go: 格式化 golang 代码 tidy: 去掉未应用的我的项目依赖 clean: 清理临时文件 help: Makefile 帮忙启动我的项目go run cmd/main.go configs/app-local.yaml打包make build打包后的可执行文件生成在.dist目录 docker打包 # 镜像名和版本能够本人定义docker build . -t web-app:1.0.0启动 # APP_ENV 启用不同环境配置docker run -p 8080:8080 -e APP_ENV=test --name webapp web-app:1.0.0技术选型gin - web 框架json-iterator - 高效 json 类库go-yaml - yaml 文件加载xorm - orm 框架go-redis redis 客户端lo 一个相似 lodash 的汇合工具类库工程构造build: 工程构建相干cmd: 利用启动入口configs: 我的项目配置deployments: 利用依赖init: 利用启动配置internal: 利用业务逻辑代码pkg: 放到利用内部仍然能应用的代码库、工具类test: 测试相干tools: 我的项目工具,如代码生成脚本参考go 我的项目分层构造

March 24, 2023 · 1 min · jiezi

关于go:test-ssh

WebSocket:全双工通信技术,客户端与服务端均可互相发送数据,支流服务器与客户端均反对 SpringBoot开发WebSocket

March 23, 2023 · 1 min · jiezi

关于go:API网关开源Apinto网关访问策略一

背景介绍Apinto是一款高性能、可扩大、易保护的API网关。Apinto网关基于GO语言模块化开发,5分钟极速部署,配置简略、易于保护,反对集群与动静扩容,企业级开箱即用。Apinto除了提供丰盛的网关插件外,还将提供监控告警、用户角色等企业插件,同时反对自定义网关插件和可扩大企业插件,满足咱们企业的定制化需要。Apinto反对代理内部流量,转发给外部服务,也反对外部服务之间的通信代理 需要痛点许多企业和组织面临着网关访问控制的挑战,因为传统的访问控制办法往往过于轻便和繁琐。这些办法可能波及简单的规定集、繁琐的手动配置过程、不足灵活性和可扩展性等问题。此外,随着云计算和挪动设施的广泛应用,访问控制的复杂性和挑战水平也一直减少。因而,许多组织须要一种更智能、更简略、更牢靠的网关拜访策略,以确保其网络和数据的安全性和可用性。 性能介绍在Apinto中,您能够通过拜访策略对利用、API、上游服务、IP等多个维度进行黑白名单访问控制。此外,咱们还反对应用多个拜访策略进行逐层匹配,以进一步满足您的平安需要。配置步骤咱们设置一个 IP 地址,该IP只能用于申请门路为 /api/test 的API接口。如果尝试申请其余门路,申请将被回绝,无法访问。 新建拜访策略这个策略只针对特定的IP流量进行筛选,其余IP则不受影响。该策略的失效范畴限定于API门路。如果拜访规定为容许,那么只有特定的IP能力拜访该门路的API;反之,如果拜访规定为回绝,则特定的IP只能拜访除该门路外的API。公布拜访策略 测试后果通过测试后果,咱们能够看到,拜访 /api/test 时会返回响应后果。然而,当拜访 /api/test1 或 /api/test2 时,会失去拜访 {IP} 的申请被回绝的提醒。

March 23, 2023 · 1 min · jiezi

关于go:golang-打桩mock-数据怎么玩

工作中,很多公司都要求效力,要求自动化测试 理论落地的过程中发现,要做单元测试,自动化测试,可能以后这个服务会依赖其余服务的数据,接口等等 那么单测或者自动化的过程中,就可能会因为其余服务的起因或者环境因素导致测试失败,或者阻塞测试 这是一个问题,必须得解决,咱们能够采纳 golang 自带的 mock 工具来实现,能够在一些必要的中央进行数据打桩,mock 数据 gomock 是什么?是官网提供的 一个 mock 数据的 框架 官网还提供了 mockgen 工具用来帮忙 咱们 生成测试代码 github 上我的项目地址是:https://github.com/golang/mock 官网是这样介绍 gomock 的: gomock 是一个用于Go 编程语言的 mocking 框架。它与 Go 的内置测试包集成得很好,但也能够在其余环境中应用。如何应用 gomock?应用 gomock 也是非常简单的,先 go get 对应的 工具 gomock 和 mockgen go get -u github.com/golang/mock/gomockgo get -u github.com/golang/mock/mockgen能够写一个 demo 来进行实际目录构造是这样的 gomock_test├── go.mod├── go.sum├── main.go└── myfunc ├── mock_myfunc.go ├── myfunc.go ├── myuser.go └── myuser_test.go mock_myfunc.go 是应用 mockgen 工具生成的myfunc.go 次要是用于模仿调用的底层实现myuser.go 次要是去调用 myfunc.go 外面的接口myuser_test.go 是 对应的单测文件myfunc.go ...

March 22, 2023 · 3 min · jiezi

关于go:Go语言开发环境轻松搭建指南

Go 语言是由谷歌公司在 2007 年开始开发的一门语言,目标是能在多外围时代高效编写网络应用程序。Go 语言的创始人 Robert Griesemer、Rob Pike 和 Ken Thompson 都是在计算机倒退过程中作出过重要奉献的人。自从 2009 年 11 月正式公开公布后,Go 语言迅速席卷了整个互联网后端开发畛域,其社区里不断涌现出相似 vitess、Docker、etcd、Consul 等重量级的开源我的项目。 互联网在一直的倒退,越来越多的企业抉择应用Go来进行开发,同时也非常适合游戏、web、网络编程等多种利用场景。然而,想要开始应用Go语言开发,必须要先进行环境搭建。 一、下载安装Go环境。首先在官网下载页面,咱们能够找到适宜本人操作系统的安装包。下载实现后,进行双击装置即可。装置实现之后,咱们须要设置Go语言的环境变量。在Windows零碎中,关上“控制面板”,而后抉择“零碎和平安”-“零碎”-“高级零碎设置”-“环境变量”,在零碎变量中找到“Path”,并进行编辑,在新的一行中增加Go的装置门路即可。 二、装置Go语言的开发工具。目前,比拟风行的开发工具有LiteIDE、Goland、Visuai Studio Code等。在这里,咱们举荐应用Visuai Studio Code,因为它不仅功能强大,而且还有丰盛多的插件反对。咱们能够在官网上下载安装,而后在装置商店装置Go的插件即可。 三、测试。装置实现之后,咱们能够测试一下Go语言是否装置胜利,关上命令行工具,输出“go version",如果返回Go语言的版本号,则阐明装置胜利。此时,咱们就能够欢快地开始Go语言开发了。总的来说,Go语言的环境搭建并不是很简单,只需依照上述步骤一次操作即可。对于想要应用Go语言有搭建好了稳固的开发环境,能力更好地进行后续的开发工作。老手学习Go语言怎么样?难度大吗?作为一个绝对较新的语言,Go有着本人独特的劣势。首先,它的语法简洁明了,易于了解,不易出错。其次,Go语言的并发模型非常先进,能够实现高并发的程序编写,这在当下疾速倒退的时代尤为重要。此外,Go语言还具备良好的跨平台个性,可能在多种不同操作系统和软件上运行。对于初学者来说,学习Go语言并不难。具备一些编程教训的能更快的把握Go语言的根底语法。对于齐全没有教训的老手,也能够通过相干课程和实际我的项目来逐步相熟并把握Go语言的基本知识。当然,也能够抉择并关注成都雅心教育,理解更多IT资讯,还有收费课程等你支付。尽管Go语言有很多长处,但也有须要留神的中央。比方,因为Go语言的非凡语法,须要肯定的工夫去适应它的写法。此外,一些Go语言的个性也须要肯定的工夫和教训来了解和把握。 总之,学习Go语言对初学者来说是一项值得尝试的挑战。在学习过程中,须要放弃急躁和继续的致力,逐步提高本人的编程程度,也有利于本身的竞争力。

March 22, 2023 · 1 min · jiezi

关于go:Go-框架bind-函数gin-框架中是如何绑定请求数据的

大家好,我是渔夫子。 在gin框架中,咱们晓得用bind函数(或bindXXX函数)可能将申请体中的参数绑定到对应的构造体上。同时,你也会发现在gin中有很多bind或bindXXX函数,比方ShouldBind、ShouldBindQuery、ShouldBindHeader、ShouldBindJSON等等。那么,他们之间有什么不同呢?本文带你深刻理解这些bind函数的应用。 一、bind的根本作用在gin框架或其余所有web框架中,bind或bindXXX函数(后文中咱们对立都叫bind函数)的作用就是将申请体中的参数值绑定到对应的构造体上,以不便后续业务逻辑的解决。 接下来咱们看一个简略的应用例子,该实例是冀望客户端发送一个JSON格局的申请体,而后通过JSON标签绑定到LoginRequest构造体上。如下: package mainimport ( "fmt" "github.com/gin-gonic/gin")type LoginRequest struct { Username string `json:"username"` Password string `json:"password"`}func main() { g := gin.New() g.POST("/login", func(ctx *gin.Context) { r := &LoginRequest{} ctx.ShouldBind(r) fmt.Printf("login-request:%+v\n", r) }) g.Run(":9090")}运行上述示例代码,并在postman中或应用curl给http://localhost:9090/login发送申请,申请体是: curl -X POST -H "Content-Type:application/json" http://localhost:9090/login -d '{"username": "yufuzi", "password": "123456}'在代码中,咱们通过ctx.ShouldBind(r)函数,将申请体的内容绑定到了LoginRequest类型的r变量上。咱们通过ShouldBind函数的源代码能够梳理到绑定函数的个别流程: 1、调用ctx.ShouldBind函数 2、ShouldBind函数依据申请的办法(POST还是GET)以及Content-Type获取具体的bind实例。如是POST申请且申请体是JSON格局,那么就返回jsonBinding构造体实例。 3、调用ctx.ShouldBindWith函数 4、ShouldBindWith函数调用具体的绑定实例的Bind办法。例如jsonBinding.Bind函数 5、将request中的Body(或Form、Header、Query)中的申请值绑定到对应的构造体上。 其大抵流程如下: 二、申请数据起源由第一节咱们理解到,数据来源于客户端发来的申请。那么,在一次http申请中,都能够通过哪里来携带参数呢?依据http协定的规范,能够通过url中的查问参数,申请头、申请体等路径将参数传递给服务端。 在申请体中参数能够是不同的格局,比方JSON格局、XML格局、YAML格局、TOML格局、Protobuf message等。也能够是form表单的模式。 有了起源,接下来看看各个bind函数是如何把不同数据源的数据绑定到构造体上的。 三、bind及其bindXXX函数为了可能不便解析不同起源的申请数据及不同格局的数据,在gin框架中就对应了不同的bind及bindXXX函数来解析对应的申请数据。以下就是对应的数据起源及不同格局的函数。 ShouldBindQuery函数首先是来源于url地址中的查问参数,对应的解析函数是ShouldBindQuery,构造体中通过给字段减少query标签即可关联。如下: ShouldBindHeader函数其次是来源于申请头中的参数,对应的解析函数是ShouldBindHeader,构造体中通过给字段减少header标签即可关联。如下: ShouldBindXXX函数而后是来源于申请体中的参数,这个稍微简单。若申请体是一般的文本格式的话,能够是JSON、XML、TOML、YAML或者protobuf、msgpack格局。能够对应ShouldBindXXX函数,如下: 若申请体是以表单模式发送数据的,会有formBinding、formPostBinding以及formMultipartBinding三个构造体。那这三个binding有什么区别呢?要想搞清楚三个构造体之间的区别,就要从form的enctype属性说起。 form的enctype属性在html中,咱们发送表单时个别会用<form>标签,但form标签有一个enctype属性,该属性个别有两个值:multipart/form-data和application/x-www-form-urlencoded。这两个值什么意思呢? 属性为application/x-www-form-urlencodedenctype为该属性时,代表将form中的值在发送给服务端时,会将form中的值组织成key1=value1&key2=value2这样的类型发送。如下: ...

March 22, 2023 · 1 min · jiezi

关于go:学习Linux只要学会这个命令就够了

大家好,我是良许。 这段时间又是搬家,又是找新办公室,当初终于安顿下来了,有工夫给大家分享干货了。 明天给大家介绍一个 Linux 超级实用命令,有了这个命令,你就能够欢快应用 Linux 上简直所有常用命令了,再也不必放心记不住那么多选项啦~ 咱们晓得,Linux 零碎总共有 300~500 个命令,甚至有些发行版还更多。每个命令又有 N 多的选项,这样算下来,你要记住每个命令的所有用法,简直是一件不可能的事件。 那么碰上不会用的命令时,咱们个别是怎么做的呢?没错,就是找男人……额。。不对,就是 man 一下。 与 man 相似的还有 help 、info 等等命令。但这些命令有个共同点,就是给你的信息超级超级长,看过来跟天书一样。对于英文不太好的童鞋,那更加要命。 尽管你们见过屡次了,还是再截个图再挫伤你们一次: 同样地,whereis 和 whatis 尽管不长,但给出的信息基本上没什么卵用。 当初隆重介绍本文的配角—— cheat ! 这个命令是干啥用的呢? 从字面上来看,它的作用就是「小抄」。它不会给你一大堆简明扼要的货色,而是直奔主题,间接通知你这个命令该怎么用。 给个简略的案例让你们感受一下吧。 比方我想晓得网络工具 netstat 是怎么用的,有哪些罕用的参数,只须要简略输出以下命令就能够查问: $ cheat netstat 看看这后果,没半句废话,间接上案例,把你安顿得明明白白! 而且,它还贴心地通知你,netstat 命令当初曾经用得不多了,倡议用 ss 命令来代替。 反观 man 手册…… 我的天,这也太辣眼睛了吧……单单这个选项的介绍就曾经把我给劝退了…… 这或者就是程序员头发越来越少的起因吧。。 OK,当初咱们晓得 cheat 命令有如许犀利之后,咱们再来介绍一下如何装置应用这个命令。 在 Ubuntu 零碎下,只须要一条命令就能够搞定: $ sudo snap install cheat 第一次应用的时候,它会问你要不要下载配置以及手册文件,只须要一路按回车就行。 而后你就能够失常应用它了,装置的过程还是非常丝滑不便。 它的根本用法也很简略,刚刚也给过示例了: $ cheat <你想搜寻的命令>这个命令的所有用法,你也能够通过 cheat -h 来查问: ...

March 21, 2023 · 1 min · jiezi

关于go:开源API网关APINTO快速入门

公司领导对选型APINTO网关比较满意,天然少不了体验一下。首先来体验一下API网关最根本的性能:转发申请。 Apinto疾速入门从Apinto官网扒了个配置流程图,Apinto网关控制台主流程配置如下图所示: 主流程有四步,实现这四步就能够试着调用API,看网关是否胜利转发API到后端系统。 1 配置网关集群第一步:在浏览器输出控制台拜访页面进入控制台页面。 第二步:再点击基础设施菜单,开展后再点击集群治理进入集群治理列表页面,咱们间接创立集群,操作如下图所示: 第三步:新建集群如下图所示: 2 配置并公布上游服务第一步:点击上游服务菜单,开展后再点击上游治理进入上游治理列表页面,如下图所示: 第二步:点击新建上游,咱们以动态节点阐明,配置如下图所示: 第三步:把刚配置好的上游公布到集群,如下图如示: 3 配置并公布APIAPI治理是治理所有上游提供的API生命周期性能,提供按业务域分类管理、增加API、单个或批量API从不同集群高低线等性能。第一步:点击左侧导航API治理,进入API治理页面: 第二步:新建API 新建的testnews的API如下图所示: 第三步:上线该API到集群: 4 调用API在测试转发testnews这个API前,咱们先测试间接调用后端这个API,测试后果如下图所示: 阐明后端这个服务的API是失常能够调用的。 4.1 获取testnews残缺调用地址调用API的URL:网关节点的服务地址+API的申请门路:第一步:获取服务地址: 第二步:获取testnews的申请门路: 第三步:拼接地址,失去testnews这个API的残缺申请门路:网关节点的服务地址+API的申请门路 4.2 用API研发管理工具Apikit来测试测试后果与浏览器拜访后果统一,表明网关转发性能失常 5、总结Apinto网关开箱即用,整个过程仅用2个小时就能疾速入门,至于其余性能后续再进行钻研!喜爱或感兴趣的小伙伴们连忙去下载安装体验吧!为了反对Apinto团队提供更好的开源体验,我曾经fork了,你们记得fork一下噢。开源地址:https://github.com/eolinker/apinto

March 21, 2023 · 1 min · jiezi

关于go:仅仅掌握Go语言就能挽救你的编程生涯

在当今互联网时代,Go语言以其高性能、高并发和简洁易学等特点,成为了软件开发的热门抉择。从谷歌(Google)推出Go语言以来,它曾经经验了多个版本的迭代降级,逐步成熟并稳固。Go语言实用于大规模分布式系统的构建,因而,被许多企业选为构建后端服务的首选语言。越来越多的人开始学习并应用Go语言,也让Go语言的生态圈越来越丰盛。学习Go语言有助于拓宽视线、进步开发效率和待业竞争力。 Go背靠Google公司,社区十分沉闷,并且有Docker、Kubernetes这样的杀手级利用。当初,咱们曾经看到,Go是云计算时代的首选编程语言,并且,我还能够很确定的说,它正在成为下一个企业级编程语言。到底是什么让Go语言那么受欢迎呢?1.Go语言是一门十分高效的语言。它的编译速度十分快,这使得程序员们在开发过程中可能更加高效地工作。相比于其余语言,如Java和C++,Go 语言的代码量也要少得多。这意味着程序员们可能更快地编写和调试代码,从而更快地公布产品。 2.Go语言还能被宽泛用于云计算和分布式系统。因为其轻量级的个性,它可能解决大量的数据,并且在分布式系统中表现出色。当初,越来越多的公司开始应用Go语言来构建,Go语言的语法十分简洁,容易学习。其中它的代码可读性也十分高。这对老手来说是一个很大的劣势,因为他们可能更快地把握这门语言,进而高效的实现工作。 3.Go语言能够说是开发效率和运行效率二者完满的交融,同时,Go语言反对以后所有编程模式,包含过程式编程、面向对象编程以及函数式编程。程序员们能够各取所需,自由组合。 4.Go领有弱小的编译查看、严格的编码标准和残缺的软件生命周期工具,具备很强的稳定性,稳固压倒一切。那么为什么Go相比于其余程序会更稳固呢?这是因为Go提供了软件生命周期(开发、测试、部署、保护等等)的各个环节的工具,如go tool、gofmt、go test。既然学Go绝对容易,那Go适宜做什么呢?1.分布式系统。如etcd、groupcache、tidb、cockroachdb、lnfluxdb等。 2.区块链利用。区块链是古代互联网技术的最新成绩,其应用分布式账本技术来保障数据的平安和公正性。而Go语言作为一门高效、轻量级的语言,很适宜用来开发区块链利用。因为区块链利用须要保障出块速度快、交易效率高、代码平安稳固,而Go语言正好具备这些特点。 3.网络爬虫。在互联网时代,数据是企业的命根子,而爬虫是采集互联网数据的重要形式。因为爬虫须要大量的资源调度和并发解决,而Go语言的并发机制恰能胜任此工作,可能进步爬虫的效率,缩短采集工夫,为数据分析和开掘提供更多的反对。 4.服务端开发。应用C或C++做的工作,Go语言也很适配,例如日志解决、文件系统、监控零碎等。总之,Go语言简略易学,天生反对并发,完满符合当下高并发的互联网生态。Go语言的岗位需要继续低落,目前的Go程序员数量少,待遇好,学会抓住趋势。更多IT资讯请关注成都雅心教育,时刻为您答疑解惑。

March 21, 2023 · 1 min · jiezi

关于go:Go-错误处理100-提案全部被拒绝为何现阶段仍用-if-err-nil

大家好,我是煎鱼。 这些年给 Go 提新的错误处理提案的人川流不息,挡都挡不住。Ian Lance Taylor 作为历史的亲历者之一特意梳理了《language: Go 2: error handling meta issue》。 明天联合我本人写过的内容分享给大家,当前有人再问能够甩给他们,这样他就懂前因后果了。 背景在 2018 年 8 月,现任 Go 外围团队负责人 Russ Cox 给 Go2 的错误处理画了一个大大的蓝图,并介绍了一个未实现的设计草案。 具体指标如下: 冀望 Go 的谬误查看更轻量级,可能缩小被大家吐槽的谬误查看的程序文本数量。整体上要确保错误处理更加不便,复杂度不能变高。谬误检查和错误处理都必须放弃显式,这意味着在 Go 程序中是可见的。咱们不想反复异样解决的陷阱。必须保障现有的 Go 代码的兼容性,不能有破坏性降级。在此之后,也因为 Go 的热浪,许多新的提案作为 Go2 的错误处理变更提交,Go 邮件也有大量的探讨,领有许多尝试,但迄今为止没有一个被承受。 这就是当初 Go 错误处理的背景。 错误处理合集当然,这个合集并不 100% 全面,如果须要全查看一遍,能够自行在 go/issues 库搜寻 error-handling 标签就能够了。 以下是一些值得关注的错误处理提案合集: Go2 check/handle 办法: 次要起因之一:handle 和 defer 之间不足清晰度。关联文章:先睹为快,Go2 Error 的挣扎之路常被提起的 try-catch 办法: 次要起因:额定的流程管制,应用 try 的简单表达式可能导致函数返回。 Go 目前在表达式级别没有控制流构造(panic 除外),会引入额定设计。关联文章:Go try 新提案靠谱吗?想简化错误处理了像 Rust 用 ! ? 作为谬误查看: ...

March 21, 2023 · 1 min · jiezi

关于go:Go-error-源码解读错误处理的优化与最佳实践

Go 语言自从诞生起,它的错误处理机制始终被喷出翔。 没错,Go 语言在诞生初期的确简陋得不行,但在多个版本迭代以及各位前辈的摸索下还是找到了 Go 语言「错误处理」的最佳实际。 上面咱们深刻理解下 Go 的 error 包,并探讨如何让咱们的 Go 我的项目领有清新的错误处理。 Go 的 errors 包Go 中的 error 是一个简略的内置接口类型。只有实现了这个接口,就能够将其视为一种 error。 type error interface { Error() string}与此同时,Go 的 errors 包实现了这个接口:调用 errors.New() 就会返回error接口的实现类errorString,通过源码咱们看到errorString的底层就是一字符串,可真是"省事"啊。 package errorsfunc New(text string) error { return &errorString{text}}type errorString struct { s string}func (e *errorString) Error() string { return e.s}errors.New()函数返回的是errorString的指针类型,这样做的目标是为了避免字符串产生碰撞。 咱们能够做个小测试:error1和error2的 text 都是"error",然而二者并不相等。 func TestErrString(t *testing.T) { var error1 = errors.New("error") var error2 = errors.New("error") if error1 != error2 { log.Println("error1 != error2") }}---------------------代码运行后果--------------------------=== RUN TestXXXX2022/03/25 22:05:40 error1 != error2这种创立 error 的形式很常见,在 Go 源码以及三方包源码中大量呈现。 ...

March 19, 2023 · 6 min · jiezi