关于go:巨细靡遗流程控制Go-lang118入门精炼教程由白丁入鸿儒Go-lang流程结构详解EP09

流程构造就是指程序逻辑到底怎么执行,进而言之,程序执行逻辑的程序。家喻户晓,程序整体都是自上由下执行的,但有的时候,又不仅仅是从上往下执行那么简略,大体上,Go lang程序的流程控制结构一共有三种:程序构造,抉择构造,循环构造。程序构造:从上向下,逐行执行;抉择构造:条件满足,某些代码才会执行,0-1次;循环构造:条件满足,某些代码会被重复的执行屡次,0-N次 抉择构造之条件判断if/else市面上的语言都有if/else逻辑,逻辑非常简单,只有满足条件,就会执行条件代码块的逻辑: if 布尔表达式 { /* 在布尔表达式为 true 时执行 */ } if 布尔表达式 { /* 在布尔表达式为 true 时执行 */ } else { /* 在布尔表达式为 false 时执行 */ } if 布尔表达式1 { /* 在布尔表达式1为 true 时执行 */ } else if 布尔表达式2{ /* 在布尔表达式1为 false ,布尔表达式2为true时执行 */ } else{ /* 在下面两个布尔表达式都为false时,执行*/ }具体逻辑: package main import "fmt" func main() { var a int = 1 /* 应用 if 语句判断布尔表达式 */ if a < 20 { /* 如果条件为 true 则执行以下语句 */ fmt.Printf("a 小于 20\n") } fmt.Printf("a 的值为 : %d\n", a) }程序返回: ...

August 12, 2022 · 4 min · jiezi

关于go:docker-打包进阶如何优化镜像image大小

一、新建go代码我的项目1、新建目录mkdir hello && cd hello && touch main.go2、关上main.go 补充代码package mainfunc main() { println("hello world , hi")}二、docker打包-单个构建1、生成Dockerfile文件touch Dockerfile2、关上Dockerfile 补充代码#go环境FROM golang:1.19# 在容器内设置 /hello 为当前工作目录RUN mkdir /helloWORKDIR /hello# 把文件复制到当前工作目录COPY . .#执行go build生成二进制打包文件helloRUN go build -o hello ./main.go# docker run 时执行命令ENTRYPOINT ["./hello"]3、构建docker镜像 hellodocker build -t hello .此时咱们能够查看docker客户端,生成了一个 993M大小的二进制镜像!其实咱们只是写了一个 “hello world,hi” 字符串。为什么这么大?因为咱们装置了golang:1.19环境。 三、多阶段构建咱们关上Dockerfile,改成如下代码: #go环境FROM golang:1.19.0-alpine3.16 as build# 在容器内设置 /hello 为当前工作目录RUN mkdir /helloWORKDIR /hello# 把文件复制到当前工作目录COPY . .#执行go build生成二进制打包文件helloRUN go build -o hello_new ./main.goFROM alpine:3.16.2 as prodWORKDIR /hello_newCOPY --from=build /hello .# docker run 时执行命令ENTRYPOINT ["./hello_new"]此时再build ...

August 12, 2022 · 1 min · jiezi

关于go:tree转数组jsgo版本

tree转数组,两种形式 递归循环(留神,循环不能应用迭代器办法,只能应用for循环)js版本 /** * 数组 */let arr = [{name: "李四", id: 2, pid: 0},// [] {name: "王五", id: 3, pid: 0}, // [] {name: "赵六", id: 4, pid: 3}, // [] {name: "吗六", id: 9, pid: 3}, // [] {name: "张三", id: 7, pid: 9}, // [] {name: "张五", id: 10, pid: 4}, // []] /** * 数组转tree,递归模式 * @param arr * @param pid * @returns {*[]} * @constructor */function ArrayToTree(arr, pid = 0) { // 判断 arr 是否是数组 if (!Array.isArray(arr) || !arr.length) return [] let newArr = [] arr.forEach(v => { // 判断 pid 是否雷同 雷同就插入进去,切递归一下children,有值就持续递归,没值就返回[] if (v.pid == pid) { newArr.push({ ...v, children: ArrayToTree(arr, v.id) }) } }) // 返回值 return newArr} let tree = ArrayToTree(arr) /** * tree转数组,循环模式,每次减少循环的变量 * 【留神:】只能应用for 循环,不能应用es6的迭代器 * @param tree * @returns {{length}|*} * @constructor */function TreeToArrayFor(tree) { if (!Array.isArray(tree) || !tree.length) throw new Error("请传入数组") for (let i = 0; i < tree.length; i++) { if (tree[i].children) { // 每次children有值,就把值合并到原始数据tree下来,减少原始tree,for 循环 的长度也会减少 顺次解决... tree = tree.concat(tree[i].children) } } return tree} /** * tree转数组,递归模式 * @param tree * @returns {*[]} * @constructor */function TreeToArray(tree) { // 判断 tree 是否有值,无返回 [] if (!Array.isArray(tree) || !tree.length) return [] let res = [] tree.forEach(v => { // tree的每个元素都 放入到 res外面 res.push(v) if (v.children) { // 有children 就把 children数据递归 返回 顺次放到 res外面 res.push(...TreeToArray(v.children)) } }) return res} go 版本 ...

August 12, 2022 · 3 min · jiezi

关于go:go源码分析类型

一 类型是怎么实现的1、类型的根底类型咱们都晓得怎么申明一个类型。例如type T struct { Name string} 。大家有没有思考过,当咱们进行反射、接口动静派发、类型断言这些语言个性或机制,go语言是怎么辨认这些类型的呢?其实编译器会给每种类型生成对应的类型形容信息写入可执行文件,这些类型形容信息就是“类型元数据”。 数据类型尽管很多,然而不论是内置类型还是自定义类型,它的“类型元数据”都是全局惟一的。这些类型元数据独特形成了Go语言的类型零碎。如下图所示: 下面的类型都有一些公共的属性,像类型名称,大小,对齐边界,是否为自定义类型等信息,是每个类型元数据都要记录的。 type _type struct { size uintptr //数据类型占用的空间大小 ptrdata uintptr //含有所有指针类型前缀大小 hash uint32 //类型hash值 tflag tflag //额定类型信息标记 align uint8 //该类型变量对齐形式 fieldAlign uint8 //该类型构造字段对齐形式 kind uint8 //类型编号 equal func(unsafe.Pointer, unsafe.Pointer) bool//判断对象是否相等 gcdata *byte //gc数据 str nameOff // 类型名字的偏移 ptrToThis typeOff}对于具体的类型,他们的元数据是怎么存储的呢?咱们分为内置类型和自定义类型来别离剖析。 2、内置类型对于内置类型,大部分也都在runtime.type文件外面。 咱们先看看切片:elem 是存储切片内元素的类型,比方:如果是 []string,那么elem就是stringtype type slicetype struct { typ _type elem *_type //切片内元素的类型}再看看咱们上文提到的map类型:能够看到它记录了 key、value、bucket的类型和大小 type maptype struct { typ _type key *_type //key类型 elem *_type //value类型 bucket *_type // bucket类型 hasher func(unsafe.Pointer, uintptr) uintptr //hash函数 keysize uint8 elemsize uint8 bucketsize uint16 flags uint32}以上咱们只是简略举两个例子,更多的内置类型的构造参考type.go ...

August 12, 2022 · 6 min · jiezi

关于go:用Golang开发一个好看的交互式终端程序

最近写了一个用于开发交互式终端程序的库:https://github.com/fzdwx/infi...它相似js外面的Inquirer.js ,不过是用Golang写的。上面的demo是其中一个组件:autocomplete编辑切换为居中demo它次要的个性有: 提供了一系列开箱即用的组件 progress bar / progress bar groupmulti / single selectinput textspinnerconfirm反对 linux / widnwos (我手上只有这两种操作系统)基本上每个根底组件都提供了一些自定义的选项,你能够依据你的须要进行替换。 比如说多选 和单选 实际上都是基于selection 这个根底组件进行替换某些自定义选项而来的。input text 和confirm 也是基于同一个根底组件而来的。能够组合应用,你能够将多个根底组件进行组合应用 根底组件有: inputselectionprogress barspinner 等autocomplete 这个组件是input + selectionprogress bar group 就是多个progress bar 组合selection 外面的过滤性能也用到了input上面是一些运行示例: 如果有帮到你,心愿能点个star,如果遇到了bug,也欢送提issue,我会在第一工夫响应! https://github.com/fzdwx/infi...

August 12, 2022 · 1 min · jiezi

关于go:go-build-打包二进制执行文件与-用docker打包镜像image-入门

一、go打包而进驻文件1、装置go环境咱们能够从官网 https://go.dev/dl 下载对应零碎的go安装文件。我这里是 mac零碎,x86架构,所以我抉择了装置实现后执行一下 go version 输入如下: go version go1.19.7 darwin/amd642、新建一个试验目录mkdir hello && cd hello && touch main.go3、关上main.go 补充代码package mainfunc main() { println("hello world , hi")}4、build打包一个可执行二进制文件 hellogo build -o hello ./main.go此时咱们用tree命令查看一下目录: ➜ hello git:(master) ✗ tree.├── hello└── main.go0 directories, 2 files生成了一个 hello的二进制可执行文件 5、执行一下➜ hello git:(master) ✗ ./hello hello world , hi二、本地打包的环境与版本以及各种依赖问题咱们发现,在这里,咱们打包的时候,首先下载了 go的环境。如果咱们是一个团队,有很多成员,那么首先就须要每个人的环境,都得统一,这样打包后的文件能力一样。如果go版本不统一的话,那么比我的事1.14,其余热的1.19,如果用了新的办法,他在本地发现能用,但同样的代码,到我这就不能用了。 三、docker打包如果大家都用docker打包,在docker外面配置一样的环境和版本,就能够解决下面的问题。咱们先把 hello 这个文件删掉,只留下 main.go,如下: ➜ hello git:(master) ✗ tree .└── main.go0 directories, 1 file

August 11, 2022 · 1 min · jiezi

关于go:实证与虚无抽象和具象Go-lang118入门精炼教程由白丁入鸿儒Go-lang接口interface的使用EP08

看到接口这两个字,咱们肯定会联想到面向接口编程。说白了就是接口指定执行对象的具体行为,也就是接口示意让执行对象具体应该做什么,所以,普遍意义上讲,接口是形象的,而理论执行行为,则是具象的。 接口(interface)的定义在Go lang中,接口是一组办法签名,当类型为接口中的所有办法提供定义时,它被称为实现接口。和面向接口的思维十分相似,接口指定了类型应该具备的办法,类型决定了到底该怎么实现这些办法: /* 定义接口 */ type interface_name interface { method_name1 [return_type] method_name2 [return_type] method_name3 [return_type] ... method_namen [return_type] } /* 定义构造体 */ type struct_name struct { /* variables */ } /* 实现接口办法 */ func (struct_name_variable struct_name) method_name1() [return_type] { /* 办法实现 */ } ... func (struct_name_variable struct_name) method_namen() [return_type] { /* 办法实现*/ }具体实现形式: package main import ( "fmt" ) type Phone interface { call() } type Android struct { } func (android Android) call() { fmt.Println("I am Android") } type Ios struct { } func (ios Ios) call() { fmt.Println("I am Ios") } func main() { var phone Phone phone = new(Android) phone.call() phone = new(Ios) phone.call() }程序返回: ...

August 11, 2022 · 3 min · jiezi

关于go:化整为零优化重用Go-lang118入门精炼教程由白丁入鸿儒go-lang函数的定义和使用EP07

函数是基于性能或者逻辑进行聚合的可复用的代码块。将一些简单的、简短的代码抽离封装成多个代码片段,即函数,有助于进步代码逻辑的可读性和可维护性。不同于Python,因为 Go lang是编译型语言,编译之后再运行,所以函数的定义程序无关痛痒。 函数申明在 Go lang里,函数申明语法如下: func function_name(parameter_list) (result_list) { //函数逻辑 }这里应用function的简写模式 func关键词,前面顺次接 function\_name(函数名) , parameter\_list(参数列表) , result\_list(返回值列表)以及函数体 。 parameter\_list(参数列表)成员:函数的参数名以及参数类型,这些参数作为局部变量,其值由参数调用者提供,函数中的参数列表和返回值并非是必须的。 result\_list(返回值列表):函数返回值的变量名以及类型,如果函数返回一个无名变量或者没有返回值,返回值列表的括号是能够省略的。 如果有间断若干个参数的类型统一,那么只需在最初一个参数后增加该类型: package main import "fmt" // 函数返回一个无名变量,返回值列表的括号省略 func sum(x int, y int) int { return x + y } // 无参数列表和返回值 func printBookName() { fmt.Println("go lang1.18") } // 参数的类型统一,只在最初一个参数后增加该类型 func sub(x, y int) int { return x - y } func main() { fmt.Println("1 + 1 = ", sum(1, 1)) printBookName() fmt.Println("2 - 1 =", sub(2, 1)) }程序返回: ...

August 11, 2022 · 3 min · jiezi

关于go:链表高频算法题之Golang版思路清晰注释详尽

链表类的算法题在面试中是最常呈现的,题目尽管简略,但也非常考验面试者的逻辑思维和算法熟练度,以下通过几道常见的链表题来看看它们惯例的解法吧!(点击题目可到leetcode原题,不定时更新) 1、判断链表是否有环思路应用快慢指针遍历链表,快指针每次走2步,慢指针每次走1步,如果两者相遇,则有环,否则没有 package mainimport "fmt"type Node struct { Val int Next *Node}func hasCycle(head *Node) bool { if head != nil { fast := head slow := head for fast != nil && fast.Next != nil { fast = fast.Next.Next slow = slow.Next if fast == slow { return true } } } return false}2、链表的两头结点思路应用快慢指针,快指针每次走2步,慢指针每次走1步,快指针走完了,慢指针所在的地位就是两头节点 func middleNode(head *Node) *Node { if head == nil || head.Next == nil { return nil } slow := head fast := head for fast != nil && fast.Next != nil { slow = slow.Next fast = fast.Next.Next head.Printf() } return slow}3、反转链表思路遍历链表,将每个节点的next指针指向前驱节点,遍历到最初的尾节点就是新的头节点 ...

August 11, 2022 · 2 min · jiezi

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

1.数组:(1)数组是值类型(2)数组的零值是元素类型的零值(3)数组长度在创立完当前就是固定的2.切片:(1)切片是援用类型(2)切片的底层是数组(3)切片比数组多了个cap,容量(4)切片能扩容,1024一下时候每次扩容是2倍,大于1024当前一次1.25,扩容时候是拷贝数值创立新的数组

August 11, 2022 · 1 min · jiezi

关于go:gin-绑定IPV4地址

用gin写的http服务,发现部署在不同的服务器上,发现开启的协定不一样 同样是8081端口 在不同的机器上,有些是监听Ipv4地址 有些是监听Ipv6地址. 查资料后发现,在双栈零碎上默认是会优先监听IPv6地址的。如果这个事件因为非凡状况须要监听在Ipv4上应该怎么办呢? 有两种办法1:关闭系统IPv6服务2:在gin中指定绑定到IPv4上 显然第二种办法老本更低 以下为演示代码,展现如果在gin中绑定端口到IPv4.(其余GO中基于net.http包的框架同样实用) package mainimport ( "flag" "github.com/gin-gonic/gin" "net" "net/http")var forceIpv4 boolvar port = ":8081"func init() { flag.BoolVar(&forceIpv4, "forceIpv4", false, "强制指定ipv4") flag.Parse()}func main() { r := gin.Default() r.GET("/ping", func(context *gin.Context) { context.JSON(http.StatusOK, gin.H{ "message": "ok", }) }) if forceIpv4 { // 强制ipv4 server := &http.Server{Addr: port, Handler: r} ln, err := net.Listen("tcp4", port) if err != nil { panic(err) } type tcpKeepAliveListener struct { *net.TCPListener } server.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) } else { r.Run(port) }}当命令行参数forceIpv4指定为true的时候就会强制应用ipv4 ...

August 11, 2022 · 1 min · jiezi

关于go:工业制造里神奇的机械臂基于Shifu-的设备管理和应用开发

Shifu Demo使用指南 ——体验与机械臂的数字孪生进行交互Shifu是一个基于Kubernetes的物联网开发及治理的开源平台。开发者通过应用Shifu,能够更简略地连贯、监督和管制任何物联网设施。 Shifu Demo地址:https://demo.shifu.run/机械臂是指高精度,多输出多输入、高度非线性、强耦合的简单零碎,是一种十分广泛的工业控制器。因其独特的操作灵活性,已在工业拆卸、平安防爆等畛域失去广泛应用。 本文依据Shifu Demo使用指南,具体介绍Shifu极速试玩中体验与机械臂的数字孪生进行交互的内容,直观感触如何用一行命令实现对机械臂坐标数据与状态信息的获取。 ## 部署Docker与装置Shifu ### 办法 依据Shifu Demo使用指南的步骤实现"部署Docker"与"装置Shifu" 地址:https://demo.shifu.run/与机械臂的数字孪生交互1.启动Nginx咱们启动一个nginx实例来模仿应用程序与shifu之间的交互: sudo kubectl run --image=nginx:1.21 nginxsudo kubectl get pods -A | grep nginx能够看到nginx曾经在运行: 2.启动机械臂虚构设施首先,咱们创立一个机械臂的数字孪生: sudo kubectl apply -f run_dir/shifu/demo_device/edgedevice-robot-arm咱们能够看到机械臂曾经失常启动: sudo kubectl get pods -A | grep robotarm 3.与机械臂虚构设施交互接着,咱们须要进入nginx:(如果您未启动Nginx,请您首先 启动Nginx服务) sudo kubectl exec -it nginx -- bash而后,咱们能够与机械臂的数字孪生通过http://deviceshifu-robotarm.d... 进行交互,失去机械臂的坐标(以下后果随机): curl http://deviceshifu-robotarm.deviceshifu.svc.cluster.local/get_coordinate;echo 此外,咱们能够与机械臂的数字孪生通过http://deviceshifu-robotarm.d... 进行交互,失去机械臂的运行状态(以下运行状态随机呈现) curl http://deviceshifu-robotarm.deviceshifu.svc.cluster.local/get_status;echo curl http://deviceshifu-robotarm.deviceshifu.svc.cluster.local/get_status;echo ccurl http://deviceshifu-robotarm.deviceshifu.svc.cluster.local/get_status;echo Q&AQ:在这个试玩中如何模仿机械臂?A:当模仿机械臂接管到get_coordinate命令后会返回其以后的x, y, z轴坐标。 本文由边无际受权公布

August 11, 2022 · 1 min · jiezi

关于go:go-命令行工具库-cobra-使用入门

一、介绍cobra库是go最罕用的命令行库。开原地址:https://github.com/spf13/cobra 二、疾速应用1、新建目录mkdir cobratest && cd cobratest2、初始化go modgo mod init sample/cobratest此时咱们关上go.mod 第一行写了咱们的包名为 sample/cobratest module sample/cobratestgo 1.14require ( github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/spf13/cobra v1.5.0 // indirect)3、装置cobrago get -u github.com/spf13/cobra@latest4、cobra初始化cobra init --pkg-name sample/cobratest咱们关上命令行应用tree命令看一下文件目录 ➜ cobratest git:(master) ✗ tree.├── LICENSE├── cmd│   └── root.go├── go.mod├── go.sum└── main.go1 directory, 5 files5、新建一个子命令cobra add cronMyFirst咱们会发现在 cmd目录同级root.go 生成了一个新的文件 cronMyFirst.go关上 cronMyFirst.go文件 package cmdimport ( "fmt" "github.com/spf13/cobra")// cronMyFirstCmd represents the cronMyFirst commandvar cronMyFirstCmd = &cobra.Command{ Use: "cronMyFirst", Short: "A brief description of your command", Long: `A longer description that spans multiple lines and likely contains examplesand usage of using your command. For example:Cobra is a CLI library for Go that empowers applications.This application is a tool to generate the needed filesto quickly create a Cobra application.`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("cronMyFirst called") },}func init() { rootCmd.AddCommand(cronMyFirstCmd)}下面有一个 Use: "cronMyFirst", 也就是咱们应用的时候 只有执行 cronMyFirst就行了。 ...

August 11, 2022 · 1 min · jiezi

关于go:goalng中netrpc的使用

一、根本应用形式阐明// server/server.gopackage mainimport ( "net" "net/rpc")type Args struct { A, B int}type Calculator intfunc (t *Calculator) Add(args *Args, reply *int) error { *reply = args.A + args.B return nil}func (t *Calculator) Sub(args *Args, reply *int) error { *reply = args.A - args.B return nil}func main() { // 1. 创立 rpc 服务端 rpcServer := rpc.NewServer() // 2. 注册服务 // 待注册的服务办法必须是公开的,2 个参数都是与 client 约定好的固定类型,且为指针; // 第 1 个为 client 提交的参数,第 2 个是给 client 的返回值。 _ = rpcServer.Register(new(Calculator)) // 3. 开启监听指定的公开端口(比方此处的 8090) l, _ := net.Listen("tcp", ":8090") // 4. 周而复始同 client 建设 tcp 连贯,并开启一个 goroutine 解决 // 调用了 go server.ServeConn(conn) rpcServer.Accept(l) // 5. server.ServeConn(conn) 周而复始 接管申请、解决申请 // 6. 解决单个申请时,必然是以 gob 压缩数据, gob_encode(header) + gob_encode(body) // header 为固定的数据结构 rpc.Request{},内容含 ServiceMethod、Seq(会返回给 client,client 可能会并发申请,依据返回的 Seq 辨别是哪个申请) // 1) gob 先解析出固定构造的 header, // 2) 依据 header 中的 ServiceMethod 找到注册的服务, // 3) 依据找到的服务确定同 client 约定好的该服务的 body 构造(client 提交的参数), // 4) gob 依据 body 构造解析出申请参数信息, // 5) ServiceMethod + 参数,解决工作,实现后返回, // 6) 返回信息同样是 gob_encode(header) + gob_encode(body),header(rpc.Response{})中含 Seq,body 为同客户端约定好的返回构造,body为约定好的reply构造体}// client/client.gopackage mainimport ( "fmt" "net" "net/rpc" "sync")type Args struct { A, B int}func main() { // 1. 建设 tcp 连贯 conn, _ := net.Dial("tcp", "127.0.0.1:8090") // 2. 依据 tcp 连贯创立 client // 同时开启一个 goroutine 周而复始读取 server 返回的后果 // server 返回依照 header(rpc.Response{}: ServiceName+Seq) + body(具体服务约定好的返回构造) // 此步骤因为还没有发出请求,临时不会读取到数据 client := rpc.NewClient(conn) wg := &sync.WaitGroup{} wg.Add(2) // 3. client 能够并发发动申请 // 然而因为应用了同一个 tcp 连贯,为了不相互影响,是排队写入的 // 通过加锁,写入一个残缺的申请后[ header(rpc.Request{}: ServiceName+Seq) + body(具体的参数构造) ],再另外写入一个申请 // server 读取是依照约定,先读取 header,确定 service,再读取 body(具体的参数) go func() { args := &Args{100, 20} reply := new(int) // client.Call() 办法应用了 channel 进行阻塞,直到步骤 2 中的读取到 server 返回的数据 _ = client.Call("Calculator.Add", args, reply) fmt.Printf("Calculator.Add: %d + %d = %d\n", args.A, args.B, *reply) wg.Done() }() go func() { args := &Args{100, 20} reply := new(int) _ = client.Call("Calculator.Sub", args, reply) fmt.Printf("Calculator.Sub: %d - %d = %d\n", args.A, args.B, *reply) wg.Done() }() wg.Wait()}$ cd path/server$ go run ./server.go$ cd path/client$ go run ./client.goCalculator.Sub: 100 - 20 = 80Calculator.Add: 100 + 20 = 120二、利用已有的 DefaultServer 及 “http 转 rpc”net/rpc 包已有一个初始化好的 DefaultServer, ...

August 10, 2022 · 5 min · jiezi

关于go:一行Shifu命令接入AGV机器人快速场景开发无人搬运仓储分拣自动泊车…

Shifu Demo使用指南——体验与AGV的数字孪生进行交互Shifu是一个基于Kubernetes的物联网开发及治理的开源平台。开发者通过应用Shifu,能够更简略地连贯、监督和管制任何物联网设施。 Shifu Demo地址:https://demo.shifu.run/AGV主动导引运输车,是配备有电磁或光学等主动导引安装,可能沿规定的门路行驶,具备平安爱护以及各种移栽性能的运输车。在工业场景中,AGV无需铺设轨道、支座架等固定装置,不受场地、路线和空间的限度,实现高效、经济、灵便的无人生产。 **Shifu将AGV进行虚拟化,并在实在的客户场景下进行了验证与部署,将Shifu能力带入了工业生产现场。在将来,Shifu将帮忙更多的合作伙伴,实现对AGV设施的高效开发,最快速度实现对AGV的灵便操控。 ** 本文依据Shifu Demo使用指南,具体介绍Shifu极速试玩中体验与AGV的数字孪生进行交互的内容,直观感触如何用一行命令实现对AGV地位信息的获取。 部署Docker与装置Shifu办法依据Shifu Demo使用指南的步骤实现"部署Docker"与“装置Shifu” 指南地址:https://demo.shifu.run/与AGV的数字孪生交互1.启动Nginx咱们启动一个nginx实例来模仿应用程序与shifu之间的交互: sudo kubectl run --image=nginx:1.21 nginx sudo kubectl get pods -A | grep nginx能够看到nginx曾经在运行: 2.启动AGV虚构设施首先,咱们创立一个AGV的数字孪生: (如果您刚通过Shifu 安装包装置完Shifu,其会主动创立一个AGV数字孪生,所以您无需进行以下创立过程,请间接跳转到第三步——与AGV虚构设施交互) sudo kubectl apply -f run_dir/shifu/demo_device/edgedevice-agv咱们能够看到AGV曾经失常启动: sudo kubectl exec -it nginx -- bash接着,咱们能够与AGV的数字孪生通过 >http://deviceshifu-agv.device... 进行交互,失去AGV的以后x, y坐标: curl http://deviceshifu-agv.deviceshifu.svc.cluster.local/get_position;echo Q&AQ:在这个试玩中如何模仿AGV?A:当模仿AGV接管到get_position命令时会生成并返回设施以后地位的x、y轴坐标。 本文由边无际受权公布

August 10, 2022 · 1 min · jiezi

关于go:上万台测温设备的数字化管理从Shifu接入温度计的数字孪生开始

Shifu Demo使用指南——体验与温度计的数字孪生进行交互Shifu是一个基于Kubernetes的物联网开发及治理的开源平台。开发者通过应用Shifu,能够更简略地连贯、监督和管制任何物联网设施。 Shifu Demo地址:https://demo.shifu.run/本文依据Shifu Demo使用指南,具体介绍Shifu极速试玩中体验与温度计的数字孪生进行交互的内容,直观感触如何用一行命令实现对温度计测量后果与状态信息的获取。 ## 部署Docker与装置Shifu 疾速链接依据Shifu Demo使用指南的步骤实现“部署Docker”与“装置Shifu” 地址:https://demo.shifu.run/## 与温度计的数字孪生交互 ### 1.启动Nginx 咱们启动一个nginx实例来模仿应用程序与shifu之间的交互: sudo kubectl run --image=nginx:1.21 nginx sudo kubectl get pods -A | grep nginx能够看到nginx曾经在运行: 2.启动温度计虚构设施首先,咱们创立一个温度计的数字孪生: sudo kubectl apply -f run_dir/shifu/demo_device/edgedevice-thermometer咱们能够看到温度计曾经失常启动: sudo kubectl get pods -A | grep thermometer 3.与温度计虚构设施交互接着,咱们须要进入nginx:(如果您未启动Nginx,请您首先 启动Nginx服务) sudo kubectl exec -it nginx -- bash而后,咱们能够与温度计的数字孪生通过 >http://deviceshifu-thermomete... 进行交互,失去温度计的测量温度(以下后果随机): curl http://deviceshifu-thermometer.deviceshifu.svc.cluster.local/read_value;echo 最初,咱们能够通过 get_status 命令失去温度计以后运行状态(以下后果随机): curl http://deviceshifu-thermometer.deviceshifu.svc.cluster.local/get_status;echo curl http://deviceshifu-thermometer.deviceshifu.svc.cluster.local/get_status;echo ...

August 10, 2022 · 1 min · jiezi

关于go:go切片复制-copy-更像是一种指定开始索引的替换

一、语法go语言的内置函数 copy() 能够将一个数组切片复制到另一个数组切片中,如果退出的两个数组切片不一样大,就会依照其中较小的那个数组切片的元素个数进行复制。 func copy(dst, src []Type) int应用copy有几个特色 如果之前是两个不同的地址,copy后也是两个不同的地址,扭转其中一个不影响另一个。copy到指标slice,到底复制多少,取决于它的大小以及起始地位。更像是一种指定开始索引的替换二、应用示范1、同样的大小 func TestCopy1(t *testing.T) { from := []int{1, 2, 3} var to []int = make([]int, len(from), cap(from)) t.Logf("from slice: %[1]v, address: %[1]p\n", from) t.Logf("to slice: %[1]v, address: %[1]p\n", to) copy(to, from) t.Log("copy(to, from)后:") t.Logf("from slice: %[1]v, address: %[1]p\n", from) t.Logf("to slice: %[1]v, address: %[1]p\n", to) to[0] = 11 t.Log("to[0] = 11后:") t.Logf("from slice: %[1]v, address: %[1]p\n", from) t.Logf("to slice: %[1]v, address: %[1]p\n", to)}输入: ...

August 10, 2022 · 2 min · jiezi

关于go:30秒接入一台PLC设备用Shifu-快速实现工控软件编程

Shifu Demo使用指南 ——体验与PLC的数字孪生进行交互Shifu (GitHub 主页:https://github.com/Edgenesis/...) 是一个基于Kubernetes的物联网开发及治理的开源平台。开发者通过应用Shifu,能够更简略地连贯、监督和管制任何物联网设施。 PLC作为可编程逻辑控制器,是专门为在工业环境下利用而设计的数字运算操作电子系统。因为能够在其外部存储执行逻辑运算、顺序控制、定时、计数和算术运算等操作的指令,进而实现管制各种类型的机械设备或生产过程,所以PLC是与古代工业自动化生产倒退密不可分的设施。 Shifu曾经实现对PLC设施的虚拟化,在Shifu Demo中能够体验通过一行命令实现对PLC设施的管制,这是在数字孪生环境中对物理设施进行管制最为重要的一步。 本文依据Shifu Demo使用指南,具体介绍Shifu极速试玩中体验与PLC的数字孪生进行交互的内容。 ## 部署Docker ### 1.下载并装置Docker 安装包:https://demo.shifu.run/detail 2.查看Docker是否可用a. 关上Docker,并放弃其运行b. 在Linux/Windows/Mac 的命令行中执行以下命令 sudo docker ps如果 Docker 运行顺利,将会失去以下输入: 装置Shifu1.装置Shifu返回demo.shifu.run进行下载安装。(间接进入页面中的第二步,实现该步骤的流程后即可回到本页面) 装置实现后 Shifu 会在docker运行时随同启动。 2.查看Shifu是否启动应用以下命令来查看运行成果: sudo kubectl get pods -A如果所有 “STATUS” 都是 Running 即示意胜利: ## 与PLC的数字孪生交互 ### 1.启动Nginx 咱们启动一个nginx实例来模仿应用程序与shifu之间的交互: sudo kubectl run --image=nginx:1.21 nginxsudo kubectl get pods -A | grep nginx 能够看到nginx曾经在运行: 2.启动PLC虚构设施首先,咱们启动PLC的数字孪生: sudo kubectl apply -f run_dir/shifu/demo_device/edgedevice-plc通过如下指令,能够看到PLC设施的数字孪生曾经启动: sudo kubectl get pods -A | grep plc ...

August 10, 2022 · 1 min · jiezi

关于go:二分查找一看就会一写就废

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜寻 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1: 输出: nums = [-1,0,3,5,9,12], target = 9 输入: 4 解释: 9 呈现在 nums 中并且下标为 4 示例 2: 输出: nums = [-1,0,3,5,9,12], target = 2 输入: -1 解释: 2 不存在 nums 中因而返回 -1 提醒: 你能够假如 nums 中的所有元素是不反复的。 n 将在 [1, 10000]之间。 nums 的每个元素都将在 [-9999, 9999]之间。 原题链接:https://leetcode.cn/problems/... 思路:升序无反复元素数组,能够思考下应用二分查找法,二分查找常见公式: func binySearch(target int) (res int) { left := 0 right := …… for 条件 { mid := left + (right-left)/2 if nums[mid] == target { return mid } else if nums[mid] > target { right = …… } else if nums[mid] < target { left = …… } } return -1}留神:golang 没有while 循环 ...

August 10, 2022 · 2 min · jiezi

关于go:负载均衡原理分析与源码解读

上一篇文章一起学习了Resolver的原理和源码剖析,本篇持续和大家一起学习下和Resolver关系密切的Balancer的相干内容。这里说的负载平衡次要指数据中心内的负载平衡,即RPC间的负载平衡。 传送门 服务发现原理剖析与源码解读 基于go-zero v1.3.5 和 grpc-go v1.47.0 负载平衡每一个被调用服务都会有多个实例,那么服务的调用方应该将申请,发向被调用服务的哪一个服务实例,这就是负载平衡的业务场景。 负载平衡的第一个关键点是公平性,即负载平衡须要关注被调用服务实例组之间的公平性,不要呈现旱的旱死,涝的涝死的状况。 负载平衡的第二个关键点是正确性,即对于有状态的服务来说,负载平衡须要关怀申请的状态,将申请调度到能解决它的后端实例上,不要呈现不能解决和错误处理的状况。 无状态的负载平衡无状态的负载平衡是咱们日常工作中接触比拟多的负载平衡模型,它指的是参加负载平衡的后端实例是无状态的,所有的后端实例都是对等的,一个申请不管发向哪一个实例,都会失去雷同的并且正确的处理结果,所以无状态的负载平衡策略不须要关怀申请的状态。上面介绍两种无状态负载平衡算法。 轮询轮询的负载平衡策略非常简单,只须要将申请按程序调配给多个实例,不必再做其余的解决。例如,轮询策略会将第一个申请调配给第一个实例,而后将下一个申请调配给第二个实例,这样顺次调配上来,调配完一轮之后,再回到结尾调配给第一个实例,再顺次调配。轮询在路由时,不利用申请的状态信息,属于无状态的负载平衡策略,所以它不能用于有状态实例的负载均衡器,否则正确性会呈现问题。在公平性方面,因为轮询策略只是按程序调配申请,所以实用于申请的工作负载和实例的解决能力差异都较小的状况。 权重轮询权重轮询的负载平衡策略是将每一个后端实例调配一个权重,调配申请的数量和实例的权重成正比轮询。例如有两个实例 A,B,假如咱们设置 A 的权重为 20,B 的权重为 80,那么负载平衡会将 20% 的申请数量调配给 A,80 % 的申请数量调配给 B。权重轮询在路由时,不利用申请的状态信息,属于无状态的负载平衡策略,所以它也不能用于有状态实例的负载均衡器,否则正确性会呈现问题。在公平性方面,因为权重策略会按实例的权重比例来调配申请数,所以,咱们能够利用它解决实例的解决能力差异的问题,认为它的公平性比轮询策略要好。 有状态负载平衡有状态负载平衡是指,在负载平衡策略中会保留服务端的一些状态,而后依据这些状态依照肯定的算法抉择出对应的实例。 P2C+EWMA在go-zero中默认应用的是P2C的负载平衡算法。该算法的原理比较简单,即随机从所有可用节点中抉择两个节点,而后计算这两个节点的负载状况,抉择负载较低的一个节点来服务本次申请。为了防止某些节点始终得不到抉择导致不均衡,会在超过肯定的工夫后强制抉择一次。 在该简单平衡算法中,多出采纳了EWMA指数挪动加权均匀的算法,示意是一段时间内的均值。该算法绝对于算数均匀来说对于忽然的网络抖动没有那么敏感,忽然的抖动不会体现在申请的lag中,从而能够让算法更加平衡。 go-zero/zrpc/internal/balancer/p2c/p2c.go:133 atomic.StoreUint64(&c.lag, uint64(float64(olag)*w+float64(lag)*(1-w)))go-zero/zrpc/internal/balancer/p2c/p2c.go:139 atomic.StoreUint64(&c.success, uint64(float64(osucc)*w+float64(success)*(1-w)))系数w是一个工夫衰减值,即两次申请的距离越大,则系数w就越小。 go-zero/zrpc/internal/balancer/p2c/p2c.go:124 w := math.Exp(float64(-td) / float64(decayTime))节点的load值是通过该连贯的申请提早 lag 和以后申请数 inflight 的乘积所得,如果申请的提早越大或者以后正在解决的申请数越多表明该节点的负载越高。 go-zero/zrpc/internal/balancer/p2c/p2c.go:199 func (c *subConn) load() int64 { // plus one to avoid multiply zero lag := int64(math.Sqrt(float64(atomic.LoadUint64(&c.lag) + 1))) load := lag * (atomic.LoadInt64(&c.inflight) + 1) if load == 0 { return penalty } return load}源码剖析如下源码会波及go-zero和gRPC,请依据给出的代码门路进行辨别在gRPC中,Balancer和Resolver一样也能够自定义,同样也是通过Register办法进行注册 ...

August 10, 2022 · 5 min · jiezi

关于go:你有对象类我有结构体Go-lang118入门精炼教程由白丁入鸿儒go-lang结构体struct的使用EP06

再续前文,在面向对象层面,Python做到了超神:万物皆为对象,而Ruby,则罗唆就是神:飞花摘叶皆可对象。二者都提供对象类操作以及继承的形式为面向对象张目,但Go lang显然有一些特立独行,因为它没有传统的类,也没有继承,取而代之的是构造和组合的形式,也就是构造体(struct)的形式来组织代码,达到相似类的成果。 构造体struct的申明在 Go lang中应用上面的语法是对构造体的申明: type struct_name struct { attribute_name1 attribute_type attribute_name2 attribute_type ... }假如定义一个名为 Lesson(课程) 的构造体: type Lesson struct { name string //名称 target string //学习指标 spend int //学习破费工夫 }这里申明了一个构造体类型 Lesson ,它有 name 、 target 和 spend 三个属性,相当于Python中类的公有属性。 也能够把雷同类型的属性申明在同一行,这样能够使构造体变得更加紧凑: type Lesson2 struct { name, target string spend int }Lesson 称为命名的构造体(Named Structure) ,这里 Lesson 作为一种新的数据类型而存在,而它能够用于创立 Lesson 类型的构造体变量。 此外,申明构造体时也能够不必申明一个新类型,这样的构造体类型称为匿名构造体(Anonymous Structure) ,能够了解为构造体变量: var MyLesson struct { name, target string spend int }构造体struct的创立申明了构造体之后,咱们能够依据申明好的构造体类型来创立构造体,这个过程有点像Python语言中类的实例化: ...

August 9, 2022 · 5 min · jiezi

关于go:借问变量何处存牧童笑称用指针Go-lang118入门精炼教程由白丁入鸿儒go-lang指针的使用EP05

指针是指什么?指针是存储另一个变量的内存地址的变量。变量是一种使用方便的占位符,用于援用计算机内存地址,一个指针变量能够指向任何一个值的内存地址它指向那个值的内存地址。类比的话,指针就是书籍中的目录,自身也占据书页,既能够通过目录取得章节内容,又能够指向具体章节的页数(地址)。 指针申明申明指针,*T是指针变量的类型,它指向T类型的值: var var_name *var-typevar-type 为指针类型,var\_name 为指针变量名,* 号用于指定变量是作为一个指针。 例如: var ip *int /* 指向整型*/ var fp *float32 /* 指向浮点型 */之前咱们已经应用&关键字来获取变量在内存中的地址,事实上,该对象就是指针: package main import "fmt" func main() { var a int = 20 /* 申明理论变量 */ var ip *int /* 申明指针变量 */ ip = &a /* 指针变量的存储地址 */ fmt.Printf("a 变量的地址是: %x\n", &a) /* 指针变量的存储地址 */ fmt.Printf("ip 变量的存储地址: %x\n", ip) /* 应用指针拜访值 */ fmt.Printf("*ip 变量的值: %d\n", *ip) }由此可见,指针变量的类型为 *Type,该指针指向一个 Type 类型的变量。指针变量最大的特点就是存储的某个理论变量的内存地址,通过记录某个变量的地址,从而间接的操作该变量。 ...

August 8, 2022 · 4 min · jiezi

关于go:兼容并蓄广纳百川Go-lang118入门精炼教程由白丁入鸿儒go-lang复合容器类型的声明和使用EP04

书接上回,容器数据类型是指一种数据结构、或者抽象数据类型,其实例为其余类的对象。 或者说得更具体一点,它是以一种遵循特定拜访规定的办法来存储对象。 容器的大小取决于其蕴含的根底数据对象(或数据元素)的个数。Go lang中罕用的容器数据有数组、切片和汇合。 数组数组是一个由长度固定的特定类型元素组成的序列,一个数组能够由零个或多个元素组成,它是一种线性的数据结构,同时外部元素的内存地址是相连的,没错,Python中的元祖(tuple)和Go lang中的数组就是一类货色,因为定长的个性,所以在系统资源占用层面具备肯定的劣势。 咱们能够应用 [n]Type 来申明一个数组。其中 n 示意数组中元素的数量, Type 示意每个元素的类型: package main import "fmt" func main() { // 申明时没有指定数组元素的值, 默认为零值 var arr [5]int fmt.Println(arr) arr[0] = 1 arr[1] = 2 arr[2] = 3 fmt.Println(arr) }程序返回: [0 0 0 0 0] [1 2 3 0 0]除此之外,也可通过海象操作符等形式进行申明: package main import "fmt" func main() { // 间接在申明时对数组进行初始化 var arr1 = [5]int{15, 20, 25, 30, 35} fmt.Println(arr1) // 应用短申明 arr2 := [5]int{15, 20, 25, 30, 35} fmt.Println(arr2) // 局部初始化, 未初始化的为零值 arr3 := [5]int{15, 20} // [15 20 0 0 0] fmt.Println(arr3) // 能够通过指定索引,不便地对数组某几个元素赋值 arr4 := [5]int{1: 100, 4: 200} fmt.Println(arr4) // [0 100 0 0 200] // 间接应用 ... 让编译器为咱们计算该数组的长度 arr5 := [...]int{15, 20, 25, 30, 35, 40} fmt.Println(arr5) // 定义多维数组 arr := [3][2]string{ {"1", "10"}, {"2", "3"}, {"3", "4"}} fmt.Println(arr) // [[15 20] [25 22] [25 22]] //数组取值 fmt.Println(arr[0][0]) }同时数组反对嵌套,也就是多维数组构造,最初通过数组的下标进行取值操作。 ...

August 8, 2022 · 5 min · jiezi

关于go:分门别类输入输出Go-lang118入门精炼教程由白丁入鸿儒go-lang基本数据类型和输入输出EP03

前文再续,Go lang和Python一样,根底数据类型有着很多分类,分门别类,一应俱全。它们对应着不同的应用场景,别离是:整形、浮点、字符、字符串、布尔等等。罕用的根本数据类型常常会参加日常业务逻辑的运算、判断以及输入输出操作。 整形 int整形顾名思义,就是存储的数据类型是整数,Go lang中分为有符号和无符号,简略了解就是存储范畴上的差别: 有符号整型:int8、int16、int32、int64、int。 无符号整型:uint8、uint16、uint32、uint64、uint。 package main import ( "fmt" "math" "unsafe" ) // 有符号整型 func Integer() { var num8 int8 = 127 var num16 int16 = 32767 var num32 int32 = math.MaxInt32 var num64 int64 = math.MaxInt64 var num int = math.MaxInt fmt.Printf("num8的类型是 %T, num8的大小 %d, num8是 %d\n", num8, unsafe.Sizeof(num8), num8) fmt.Printf("num16的类型是 %T, num16的大小 %d, num16是 %d\n", num16, unsafe.Sizeof(num16), num16) fmt.Printf("num32的类型是 %T, num32的大小 %d, num32是 %d\n", num32, unsafe.Sizeof(num32), num32) fmt.Printf("num64的类型是 %T, num64的大小 %d, num64是 %d\n", num64, unsafe.Sizeof(num64), num64) fmt.Printf("num的类型是 %T, num的大小 %d, num是 %d\n", num, unsafe.Sizeof(num), num) } // 无符号整型 func unsignedInteger() { var num8 uint8 = 128 var num16 uint16 = 32768 var num32 uint32 = math.MaxUint32 var num64 uint64 = math.MaxUint64 var num uint = math.MaxUint fmt.Printf("num8的类型是 %T, num8的大小 %d, num8是 %d\n", num8, unsafe.Sizeof(num8), num8) fmt.Printf("num16的类型是 %T, num16的大小 %d, num16是 %d\n", num16, unsafe.Sizeof(num16), num16) fmt.Printf("num32的类型是 %T, num32的大小 %d, num32是 %d\n", num32, unsafe.Sizeof(num32), num32) fmt.Printf("num64的类型是 %T, num64的大小 %d, num64是 %d\n", num64, unsafe.Sizeof(num64), num64) fmt.Printf("num的类型是 %T, num的大小 %d, num是 %d\n", num, unsafe.Sizeof(num), num) } func main() { Integer() println("---------------------------------------") unsignedInteger() }程序返回: ...

August 8, 2022 · 4 min · jiezi

关于go:用-Antlr-重构脚本解释器

前言在上一个版本实现的脚本解释器 GScript 中实现了根本的四则运算以及 AST 的生成。 当我筹备再新增一个 % 取模的运算符时,会发现工作很繁琐而且简直都是反复的;次要是两步: 须要在词法解析器中新增对 % 符号的反对。在语法解析器遍历 AST 时对 % token 实现具体逻辑。其中的词法解析和遍历 AST 齐全是反复工作,所以咱们可否可能简化这两步呢? AntlrAntlr 就是做帮咱们解决这些问题的常用工具,利用它咱们只须要编写词法文件,而后就能够主动生成词法、语法解析器,并且能够生成不同语言的代码。 上面以 GScript 的示例来看看 antlr 是如何帮咱们生成词法分析器的。 func TestGScriptVisitor_Visit_Lexer(t *testing.T) { expression := "(2+3) * 2" input := antlr.NewInputStream(expression) lexer := parser.NewGScriptLexer(input) for { t := lexer.NextToken() if t.GetTokenType() == antlr.TokenEOF { break } fmt.Printf("%s (%q) %d\n", lexer.SymbolicNames[t.GetTokenType()], t.GetText(),t.GetColumn()) }}//output: ("(") 0DECIMAL_LITERAL ("2") 1PLUS ("+") 2DECIMAL_LITERAL ("3") 3 (")") 4MULT ("*") 6DECIMAL_LITERAL ("2") 8Antlr 会主动将咱们的表达式解析为 token,遍历 token 时还能拿到该 token 所在的代码行数、地位等信息,在编译期间做语法查看十分有用。 ...

August 8, 2022 · 2 min · jiezi

关于go:goalng中encodinggob包的使用

留神到 encoding/gob 包是因为看到 net/rpc 包应用它编解码。 二者都是规范库下的包。 一、示例代码和执行后果// hello.gopackage mainimport ( "bytes" "encoding/gob" "fmt")type Request struct { ServiceMethod string // format: "Service.Method" Seq uint64 // sequence number chosen by client next *Request // for free list in Server}type Request3 struct { ServiceMethod string}type Request4 struct { Other int64}func main() { var err error a := &bytes.Buffer{} encoder := gob.NewEncoder(a) _ = encoder.Encode(&Request{ Seq: 23, ServiceMethod: "firstMethod", }) _ = encoder.Encode(&Request{ Seq: 9, ServiceMethod: "secondMethod", }) _ = encoder.Encode(&Request{ Seq: 16, ServiceMethod: "thirdMethod", }) _ = encoder.Encode(&Request{ Seq: 77, ServiceMethod: "fourthMethod", }) fmt.Printf("buf: %#v\n\n", a) b := bytes.NewBufferString(a.String()) decoder := gob.NewDecoder(b) ans1 := &Request{} _ = decoder.Decode(ans1) fmt.Println("ans1 err: ", err) fmt.Printf("ans1: %#v\n\n", ans1) ans2 := &Request{} err = decoder.Decode(ans2) fmt.Println("ans2 err: ", err) fmt.Printf("ans2: %#v\n\n", ans2) ans3 := &Request3{} err = decoder.Decode(ans3) fmt.Println("ans3 err: ", err) fmt.Printf("ans3: %#v\n\n", ans3) ans4 := &Request4{} err = decoder.Decode(ans4) fmt.Println("ans4 err: ", err) fmt.Printf("ans4: %#v\n\n", ans4) ans5 := &Request{} err = decoder.Decode(ans5) fmt.Println("ans5 err: ", err) fmt.Printf("ans5: %#v\n\n", ans5)}$ go run ./hello.go buf: &bytes.Buffer{buf:[]uint8{0x2f, 0xff, 0x81, 0x3, 0x1, 0x1, 0x7, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1, 0xff, 0x82, 0x0, 0x1, 0x2, 0x1, 0xd, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0xc, 0x0, 0x1, 0x3, 0x53, 0x65, 0x71, 0x1, 0x6, 0x0, 0x0, 0x0, 0x12, 0xff, 0x82, 0x1, 0xb, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0x17, 0x0, 0x13, 0xff, 0x82, 0x1, 0xc, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0x9, 0x0, 0x12, 0xff, 0x82, 0x1, 0xb, 0x74, 0x68, 0x69, 0x72, 0x64, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0x10, 0x0, 0x13, 0xff, 0x82, 0x1, 0xc, 0x66, 0x6f, 0x75, 0x72, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x1, 0x4d, 0x0}, off:0, lastRead:0}ans1 err: <nil>ans1: &main.Request{ServiceMethod:"firstMethod", Seq:0x17, next:(*main.Request)(nil)}ans2 err: <nil>ans2: &main.Request{ServiceMethod:"secondMethod", Seq:0x9, next:(*main.Request)(nil)}ans3 err: <nil>ans3: &main.Request3{ServiceMethod:"thirdMethod"}ans4 err: gob: type mismatch: no fields matched compiling decoder for Request4ans4: &main.Request4{Other:0}ans5 err: EOFans5: &main.Request{ServiceMethod:"", Seq:0x0, next:(*main.Request)(nil)}二、解读以上代码一次性编码写入 4 条数据,分 5 次读取、解码。 ...

August 8, 2022 · 2 min · jiezi

关于go:Go开发微信小程序第三方SDK推荐

本文已收录编程学习笔记。涵盖PHP、JavaScript、Linux、Golang、MySQL、Redis和开源工具等等相干内容。最近筹备用Go语言开发微信小程序,发现会调用很多微信小程序的服务端接口,并且还须要本人封装。于是想着去GitHub上看看,是否有第三方现成的SDK间接拿来应用,后果发现两个十分不错的第三方库,这里分享给大家。 SDK规范这里列举几点,集体在应用第三方开源库的一些标准版,供大家参考: 性能稳固,有上生产环境的案例。避免出现SDK问题,须要开发者本人解决。开发团队稳固,继续更新。避免出现bug前期无人修复,呈现一种相似KPI的开源我的项目。性能足够弱小。毕竟是应用开源SDK,就是为了缩小本人去开发一些额定的性能,把尽力更多的用在实现业务上。欠缺的文档。一个再好的开源我的项目,如果没有一个欠缺的文档,这无疑给使用者减少了一个门槛,同时也升高了开发效率,达不到间接应用第三方SDK的目标。easywechat用PHP开发过微信生态的产品,预计都晓得easywechat是一个开源的、非官方的第三方SDK。功能强大、装置和应用非常简单,因为它是一个规范的 Composer 包,这意味着任何满足下列装置条件的 PHP 我的项目反对 Composer 都能够应用它。间接应用上面的命令,装置就能够失常应用了。 composer require overtrue/wechatpowerwechatPowerWeChat是一款简略易用的WeChat SDK for Golang目前曾经笼罩微信公众号、微信小程序、微信领取、企业微信。性能十分的弱小,简直是把微信生态的产品都蕴含在内。在抉择它次要基于上面几个目标: 功能强大,残缺的微信生态笼罩。涵盖了微信公众号、微信小程序、微信企业号和微信领取。根本咱们接触的微信开发,也都是这几个类目。所以足够咱们应用了。开发团队稳固。PowerWechat由Artisan Cloud团队潜心研发并且也在继续更新和欠缺当中。欠缺的文档。PowerWechat有属于本人的官网,不论是微信公众号、微信小程序、微信企业号和微信领取都有独立的模块介绍如何应用,同时也有残缺的示例代码。如下微信企业号开发,如何配置每一个参数定义都有很好的阐明。 package mainimport ( "log")func main() { WeComApp, err := work.NewWork(&work.UserConfig{ CorpID: "app_id", // 企业微信的app id,所有企业微信共用一个。 AgentID: 100001, // 外部利用的app id Secret: "wecom_secret", // 外部利用的app secret OAuth: work.OAuth{ Callback: "https://wecom.artisan-cloud.com/callback", Scopes: nil, }, HttpDebug: true, }) if err != nil { panic(err) } response := WeComApp.Base.GetCallbackIp() log.Println(response)}go-wechat-miniapp-sdkgo-wechat-miniapp-sdk基于微信小程序相干接口封装,应用golang语言封装的一套微信小程序官网接口SDK。反对如下性能: 登录|用户信息订阅音讯客服音讯对立服务音讯获取小程序码...该SDK同样的,应用起来很简略,也能很快的上手。 上面是该SDK装置办法。 go get github.com/dgb8901/go-wechat-miniapp-sdk上面是根底信息配置。 package helperimport ( "github.com/dgb8901/go-wechat-miniapp-sdk/config" "github.com/dgb8901/go-wechat-miniapp-sdk/service")type wxaHelper struct { wxaService *service.WxaService}var helper = &wxaHelper{}func Init() { cfg := &config.Cfg{ AppId: "AppId", Secret: "Secret", Token: "Token", AesKey: "AesKey", MsgDataFormat: "DataFormat", } // wxaConfig := config.NewInRedis(cfg,"127.0.0.1:6379","123456") // wxaService := service.NewInRedis(redisConfig) wxaConfig := config.NewInMemory(cfg) wxaService := service.NewService(wxaConfig) helper.wxaService = wxaService}func GetWxaService() *service.WxaService { return wxaHelper.wxaService}通过GitHub提交的记录,能够看出这个SDK应该是属于集体开发。没有残缺的文档,并且更新工夫也很久了。不举荐用于生产环境,如果你是一个想本人学习如何去封装,或者想在这个根底下来实现一个本人的SDK,能够借鉴一下该SDK。 ...

August 8, 2022 · 1 min · jiezi

关于go:极客时间Go进阶训练营全新升级版第4期完结无密内置文档资料

download:极客工夫-Go进阶训练营全新升级版|第4期完结无密内置文档资料FutureTask源码深度剖析在JDK的FutureTask当中会使用到一个工具LockSupport,在正式介绍FutureTask之前咱们先熟悉一下这个工具。LockSupport次要是用于阻塞和唤醒线程的,它次要是通过包装UnSafe类,通过UnSafe类当中的方法进行实现的,他底层的方法是通过依赖JVM实现的。在LockSupport当中次要有以下三个方法: unpark(Thread thread))方法,这个方法可能给线程thread发放一个许可证,你可能通过多次调用这个方法给线程发放许可证,每次调用都会给线程发放一个许可证,然而这个许可证不能够进行累计,也就是说一个线程能够具备的最大的许可证的个数是1一个。 park()方法,这个线程会生产调用这个方法的线程一个许可证,因为线程的默认许可证的个数是0,如果调用一次那么许可证的数目就变成-1,当许可证的数目小于0的时候线程就会阻塞,因此如果线程从来没用调用unpark方法的话,那么在调用这个方法的时候会阻塞,如果线程在调用park方法之前,有线程调用unpark(thread)方法,给这个线程发放一个许可证的话,那么调用park方法就不会阻塞。 parkNanos(long nanos)方法,同park方法一样,nanos示意最长阻塞超时工夫,超时后park方法将主动返回,如果调用这个方法的线程有许可证的话也不会阻塞。 import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.LockSupport; public class Demo { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { LockSupport.park(); // 没有许可证 阻塞住这个线程 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("阻塞实现");});thread.start();TimeUnit.SECONDS.sleep(2);LockSupport.unpark(thread); //给线程 thread 发放一个许可证System.out.println("线程启动");}} 复制代码下面代码的执行后果线程启动阻塞实现复制代码从下面代码咱们可能知道LockSupport.park()可能阻塞一个线程,因为如果没有阻塞的话必定会先打印阻塞实现,因为打印这句话的线程只休眠一秒,主线程休眠两秒。在源代码当中你可能会遇到UNSAFE.compareAndSwapXXX的代码,这行代码次要是进行原子交换操作CAS,比如:UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED)))复制代码下面的代码次要是将this对象当中的内存偏移地址为stateOffset的对象拿进去与NEW进行比较,如果等于NEW那就将这个值设置为CANCELLED,这整个操作是原子的(因为可能多个线程同时调用这个函数,因此需要保障操作是原子的),如果操作胜利返回true反之返回false。如果你目前不是很理解也没关系,只需要知道它是将对象this的内存偏移为stateOffset的值替换为CANCELLED就行,如果这个操作胜利返回true,不胜利返回false。 FutureTask回顾咱们首先来回顾一下FutureTask的编程步骤: 写一个类实现Callable接口。 @FunctionalInterfacepublic interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */V call() throws Exception;}复制代码实现接口就实现call即可,可能看到这个函数是有返回值的,而FutureTask返回给咱们的值就是这个函数的返回值。 ...

August 7, 2022 · 5 min · jiezi

关于go:用Golang实现一个简单的生产者消费者模型

工作中常常会遇到一些批量解决数据的需要,如果这些数据的解决没有逻辑上的先后顺序,这时候就正好能够应用Golang的并发编程来晋升效率了,话不多说,上代码: package mainimport ( "fmt" "sync")func main() { //初始化管道来接管工作数据 ch := make(chan int, 10000) //所有工作执行结束才完结过程 wg := &sync.WaitGroup{} //用来管制协程数量,超过50个会阻塞 pool := make(chan struct{}, 50) //工作数量 count := 1000 go producer(ch, count, wg) consumer(ch, pool, wg) wg.Wait() fmt.Println("工作处理完毕")}//生产者func producer(ch chan int, count int, wg *sync.WaitGroup) { defer close(ch) wg.Add(count) for i := 0; i < count; i++ { ch <- i fmt.Println("工作", i, "生产结束") }}//消费者func consumer(ch chan int, pool chan struct{}, wg *sync.WaitGroup) { for c := range ch { pool <- struct{}{} <-pool go handler(c, wg) }}//具体生产逻辑func handler(c int, wg *sync.WaitGroup) { defer wg.Done() fmt.Println("工作", c, "生产结束")}producer是生产者,外面批量生产业务数据,放到一个有缓冲管道里consumer是消费者,起多个协程生产管道里的数据,而协程的数量天然须要管制,怎么管制呢?通过pool这个有缓冲管道,机制就是每生产一条数据就往pool里发送一条数据,生产完读出,这样同时最多有50个工作同时在解决,超过则会阻塞期待其余协程处理完毕。wg用来期待子协程处理完毕这种模型的劣势在于利用简略、容易管制,goroutine自身很轻便,仅损耗极少许的内存空间和调度,在解决数据量级不大、业务逻辑不太简单的状况利用是足够的,然而数据量级在几百万、几千万的时候还是这样频繁的创立goroutine,会节约大量调度goroutine和内存空间。 ...

August 6, 2022 · 1 min · jiezi

关于go:ffmpeg-视频音频处理

###咱们想着将原音频和配音音频合并成一条音频,这里就须要进行音频同轨了。其命令是:ffmpeg -y -i D:\\ffmpeg_test\\org_video_sound_input.wav -i D:\\ffmpeg_test\\org_voice_input.wav -filter_complex amix=inputs=2:duration=longest D:\\ffmpeg_test\\org_voice_output.wav##将音频左右声道离开,用到ffmpeg的map_channelffmpeg -y -i source.wav -map_channel 0.0.0 01left.wav -map_channel 0.0.1 01right.wav###音频截取,截取0秒到10秒; 用 -ss 和 -t 选项,从第30秒开始,向后截取10秒的视频ffmpeg -y -i source.wav -vn -acodec copy -ss 00:00:00 -t 00:00:08.784 ouput1.wavffmpeg -y -i source.wav -vn -acodec copy -ss 00:00:09.900 -t 00:00:00.530 ouputpe2.wavffmpeg -y -i source.wav -ss 00:00:09.900 -c copy -t 00:00:00.530 -codec copy ouputpe2.wav//to 示意从什么工夫点完结ffmpeg -y -ss 00:00:00 -to 00:00:08.784 -i source.wav -vn -acodec copy ouput1.wavffmpeg -y -ss 00:00:09.900 -to 00:00:10.150 -i source.wav -vn -acodec copy ouputpe2.wav####补白,手动生成一条250ms 长的空白音频: test.wav,设置采样率 8000, -ac 1 设置声道数为1# -ac 1:声道数量转成1 -ar 22050:采样率转成22050Hz -ab 64k:比特率转成64kbffmpeg -f lavfi -t 00:00:00.500 -i anullsrc -ar 8000 test3.wav -y####音频拼接,将多个wav按程序拼接生成一个wavffmpeg -y -i "concat:ouput1.wav|test3.wav|ouputpe2.wav" -acodec copy result2.wav###将3个音频合成一个ffmpeg -y -i ouput1.wav -i test3.wav -i ouputpe2.wav -filter_complex "[0:0] [1:0] [2:0] concat=n=3:v=0:a=1 [a]" -map "[a]" outputEnd.wav###设置采样率ffmpeg -i 1.mp3 -i 2.mp3 -i 3.mp3 -filter_complex [0:0][1:0][2:0]concat=n=3:v=0:a=1[a] -map [a] -b:a 32k -ar 8000 4.mp3###双声道转单声道ffmpeg -i 99.wav -ac 1 10.wavGo应用示例代码: ...

August 6, 2022 · 1 min · jiezi

关于go:用golang写的终端命令行组件库

我的项目地址: githubgitee简介: 次要用于开发终端(命令行)的程序,它默认提供一些交互式的组件库,例如 multi selectsingle selectconfirmspinner同样也提供一些更根底的component input#componentselection#componentspinner#component你能够将它们组合起来,或者封装你想要的形态,比如说multi select和 single select 的根底组件就是selection#component; input text和 confirm是基于input#component. 一些demo:

August 6, 2022 · 1 min · jiezi

关于go:牛刀小试基本语法Go-lang118入门精炼教程由白丁入鸿儒go-lang基本语法和变量的使用EP02

书接上回,Go lang1.18首个程序的运行犹如一声悠扬的长笛,标记着并发编程的Go lang巨轮正式开始起航。那么,在这艘巨轮之上,咱们首先该做些什么呢?当然须要理解最根本的语法,那就是根底变量的申明与应用。 变量的申明与应用变量是什么玩意?是具体的数据被内存存储之后内存地址的名称。说白了就是内存中的门牌号,在go lang中申明变量有很多种形式,绝对谨严的: package main // 申明 main 包 import f "fmt" // 导入 fmt 包,打印字符串时须要用到 func main() { // 申明 main 主函数入口 //申明变量 var name int name = 1 f.Println(name) }1这里用var关键字申明变量name,变量名称能够是字母或下划线结尾,由一个或多个字母、数字、下划线组成。随后指定数据类型,这里是整形,接着进行赋值操作,如果没有赋值动作,go lang会主动填充一个默认值: package main // 申明 main 包 import f "fmt" // 导入 fmt 包,打印字符串时须要用到 func main() { // 申明 main 主函数入口 //申明变量 var name int f.Println(name) }0绝对简略一点的申明形式: package main // 申明 main 包 import f "fmt" // 导入 fmt 包,打印字符串时须要用到 func main() { // 申明 main 主函数入口 //申明变量 var name = 1 f.Println(name) }如果一个变量有一个初始值,go lang将主动可能应用初始值来推断该变量的类型。因而,如果变量具备初始值,则能够省略变量申明中的类型,也就是说一个,你得提前让go lang晓得这个变量的数据类型,无论是通过那种形式。 ...

August 5, 2022 · 4 min · jiezi

关于go:CGO-初步认知和基本数据类型转换

CGO 是什么?CGO 是 GO 语言外面的一个个性,CGO 属于 GOLANG 的高级用法,次要是通过应用 GOLANG 调用 CLANG 实现的程序库 应用咱们能够应用 import "C" 来应用 CGO 这个个性 一个最简略的 CGO 应用 package main//#include <stdio.h>import "C"func main(){ C.puts(C.CString("Hello, Cgo\n"))}import "C" 的上方能够写须要导入的库 C 库,须要正文起来,CGO 会将此处的正文内容当做 C 的代码,被称为序言(preamble) 上述代码的性能解释 应用 CGO 包的 C.CString 函数将 Go 语言字符串转为 C 语言字符串 最初调用 CGO 包的 C.puts 函数向规范输入窗口打印转换后的 C 字符串 应用 go build -x main.go 编译一下 加上 -x 能够打印出编译过程中执行的指令 # go build -x main.goWORK=/tmp/go-build594331603mkdir -p $WORK/b001/cat >$WORK/b001/importcfg.link << 'EOF' # internalpackagefile command-line-arguments=/root/.cache/go-build/fb/fbb37eeb6735cb453f6d92e2e3f46f14d9dceb5baa1cdd10aae11d1d47d60e55-dpackagefile runtime/cgo=/usr/local/go/pkg/linux_amd64/runtime/cgo.apackagefile syscall=/usr/local/go/pkg/linux_amd64/syscall.apackagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.apackagefile errors=/usr/local/go/pkg/linux_amd64/errors.apackagefile internal/bytealg=/usr/local/go/pkg/linux_amd64/internal/bytealg.apackagefile internal/oserror=/usr/local/go/pkg/linux_amd64/internal/oserror.apackagefile internal/race=/usr/local/go/pkg/linux_amd64/internal/race.apackagefile internal/unsafeheader=/usr/local/go/pkg/linux_amd64/internal/unsafeheader.apackagefile sync=/usr/local/go/pkg/linux_amd64/sync.apackagefile internal/cpu=/usr/local/go/pkg/linux_amd64/internal/cpu.apackagefile runtime/internal/atomic=/usr/local/go/pkg/linux_amd64/runtime/internal/atomic.apackagefile runtime/internal/math=/usr/local/go/pkg/linux_amd64/runtime/internal/math.apackagefile runtime/internal/sys=/usr/local/go/pkg/linux_amd64/runtime/internal/sys.apackagefile internal/reflectlite=/usr/local/go/pkg/linux_amd64/internal/reflectlite.apackagefile sync/atomic=/usr/local/go/pkg/linux_amd64/sync/atomic.aEOFmkdir -p $WORK/b001/exe/cd ./usr/local/go/pkg/tool/linux_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=Vv0to6CWqbWf5_KTN66F/K36AEO-x4qJ_LJbz5wgG/HVbBbLSaW0sTSwlN8TzN/Vv0to6CWqbWf5_KTN66F -extld=gcc /root/.cache/go-build/fb/fbb37eeb6735cb453f6d92e2e3f46f14d9dceb5baa1cdd10aae11d1d47d60e55-d/usr/local/go/pkg/tool/linux_amd64/buildid -w $WORK/b001/exe/a.out # internalmv $WORK/b001/exe/a.out mainrm -r $WORK/b001/尝试本人写一个 C 函数,让 GO 来调用他 ...

August 4, 2022 · 3 min · jiezi

关于go:Go十大常见错误第4篇forswitch和forselect做break操作的注意事项

前言这是Go十大常见谬误系列的第4篇:for/switch和for/select做break操作退出的注意事项。素材来源于Go布道者,现Docker公司资深工程师Teiva Harsanyi。 本文波及的源代码全副开源在:Go十大常见谬误源代码,欢送大家关注公众号,及时获取本系列最新更新。 场景案例1大家看看上面这段代码: for { switch f() { case true: break case false: // Do something }}如果函数调用f()返回的后果是true,进入到case true分支,会产生什么?会退出for循环么? 答案是:只退出了switch语句,并不会退出for循环,所以break后又继续执行for循环里的代码。 案例2再看上面这段代码 for { select { case <-ch: // Do something case <-ctx.Done(): break }}同样地,如果执行了break语句,退出的只是select语句块,并不会退出for循环。 那在下面2种场景里,如何退出for循环呢? 能够联合label和break进行实现。 loop: for { select { case <-ch: // Do something case <-ctx.Done(): break loop } }对于下面的代码,loop是一个label,break loop如果执行了就会退出for循环。 举荐浏览Go十大常见谬误第1篇:未知枚举值Go十大常见谬误第2篇:benchmark性能测试的坑Go十大常见谬误第3篇:go指针的性能问题和内存逃逸Go switch应用阐明Go for/break应用阐明Go select语义开源地址文章和示例代码开源在GitHub: Go语言高级、中级和高级教程。 公众号:coding进阶。关注公众号能够获取最新Go面试题和技术栈。 集体网站:Jincheng's Blog。 知乎:无忌。 福利我为大家整顿了一份后端开发学习材料礼包,蕴含编程语言入门到进阶常识(Go、C++、Python)、后端开发技术栈、面试题等。 关注公众号「coding进阶」,发送音讯 backend 支付材料礼包,这份材料会不定期更新,退出我感觉有价值的材料。还能够发送音讯「进群」,和同行一起交流学习,答疑解惑。 Referenceshttps://itnext.io/the-top-10-...https://github.com/jincheng9/...https://github.com/jincheng9/...

August 4, 2022 · 1 min · jiezi

关于go:golang从入门到入土五作用域与包

go的包官网包 在go-src/src第三方包 gopath/src go get go install会装置在这个目录下包查找 会将import的包减少 gopath/src 去查找包包别名 abc “github.com/xxx/xx” 别名定义成abc包名为所在目录的目录名(一级目录)main和init办法 init办法会在main办法之前调用会依据引入包的程序,先顺次调用每个包的init 而后调用main,包外面依据文件名一次调用每个文件的initinit能够用来初始化能够在一个文件中定义多个init办法,会顺次调用,不会重写,不会报错main包能够有多个,main办法只能有一个go的作用域函数外部为局部变量函数 办法内部,对以后包课件函数内部并且首字母大写,所有包可见,首字母大写函数名,其余包能力用如果一个main办法中的全局变量和引入的某个包里的全局变量重名,包会读取本人包内全局变量的值

August 4, 2022 · 1 min · jiezi

关于go:Go-String-解析

一、String 构造定义// src/runtime/string.go:stringStructtype stringStruct struct { str unsafe.Pointer len int} String 类型在Go语言内存模型中其实是一个“描述符”,用一个2字节的数据结构示意,它自身并不真正存储字符串数据,而仅是由一个指向底层存储的指针和字符串的长度字段组成的。 str:指向字符串底层存储首地址的指针,1字节。len:字符串的长度,1字节。 因而,咱们即使间接将 String 类型变量作为函数参数,其传递的开销也是恒定的,不会随着字符串大小的变动而变动。 二、String 个性1. String 类型的值在它的生命周期内不可扭转type stringStruct struct { str unsafe.Pointer len int}func main() { var s string = "hello" s[0] = 'a' //谬误:无奈给s[0]赋值,因为字符串内容是不可扭转的 fmt.Printf("%#v\n", (*stringStruct)(unsafe.Pointer(&s))) //输入:&main.stringStruct{str:(unsafe.Pointer)(0x2b599c), len:5} s = "world" //批改字符串,字符串底层构造体中str指针曾经发生变化 fmt.Printf("%#v\n", (*stringStruct)(unsafe.Pointer(&s))) //输入:&main.stringStruct{str:(unsafe.Pointer)(0x2b5a00), len:5} fmt.Printf("%#v\n", (*[5]byte)((*stringStruct)(unsafe.Pointer(&s)).str)) //输入:&[5]uint8{0x77, 0x6f, 0x72, 0x6c, 0x64} 别离对应 w o r l d 的 ASCII 码}因为runtime.stringStruct构造是非导出的,不能间接应用,所以手动定义了一个stringStruct构造体。String 类型的数据不可扭转的个性,进步了字符串的并发安全性和存储利用率。 字符串能够被多个协程共享,开发者不必再放心字符串的并发平安问题。针对同一个字符串值,无论它在程序的几个地位被应用,编译器只须要为它调配一块存储,大大提高了存储利用率。2. 没有结尾’\0’,存储了字符串长度Go 字符串中没有结尾’\0’,并且存储了字符串长度,获取字符串长度的工夫复杂度是常数,无论字符串中字符个数有多少,咱们都能够疾速失去字符串的长度值。 ...

August 4, 2022 · 2 min · jiezi

关于go:gozero-mapreduce源码分析和简单实现

MapreduceMapreduce是一种分布式并行编程模型,在一个函数或者一次接口调用中会呈现大量的计算或者大量的调用第三方接口的状况。这个时候就能够应用Mapreduce这种变成模型,让大量的计算在一台或者多台机器上解决,最终汇总到一起输入后果。 gozero中的Mapreducegozero是一个最近比拟风行的go微服务框架,然而在这个库中也有一些比拟有意思和好用的类库,咱们能够独自援用,就比方其中的Mapreduce。官网是这么说的:在理论的业务场景中咱们经常须要从不同的 rpc 服务中获取相应属性来组装成简单对象。如果是串行调用的话响应工夫会随着 rpc 调用次数呈线性增长,所以咱们要优化性能个别会将串行改并行。 咱们晓得如果本人实现一套并行的模式还是比拟麻烦的,gozero Mapreduce就能够帮忙咱们非常容易的实现这样的成果。让咱们重点关注本人的业务逻辑的实现。 简略应用这里须要提一下的时,gozero中还提供了线程数量的管制。能够让你本人管制并行处理的线程数,免得过多的线程对服务器造成过大的耗费。同时咱们也能够传入本人的context来管制整个办法的超时和勾销逻辑。这些都封装在类库中,不须要咱们去操心。只须要传递对的参数就能够了。上面就是一个比较简单的时候,读取一个数组并行加上“:1”最终输出扭转后的数组对象。 package mainimport ( "context" "fmt" "github.com/zeromicro/go-zero/core/mr" "time")func main() { //要解决的数据 uid := []string{"a", "b", "c", "d", "e", "f"} //传递数据的逻辑 generateFunc := func(source chan<- interface{}) { for _, v := range uid { source <- v fmt.Println("source:", v) } } // 解决数据的逻辑 mapFunc := func(item interface{}, writer mr.Writer, cancel func(err error)) { tmp := item.(string) + ":1" writer.Write(tmp) fmt.Println("item:", item) } // 合并的数据逻辑 reducerFunc := func(pipe <-chan interface{}, writer mr.Writer, cancel func(err error)) { var uid []string for v := range pipe { uid = append(uid, v.(string)) fmt.Println("pipe:", uid) } writer.Write(uid) } // 开始并发解决数据 // 超时工夫 ctx, cl := context.WithTimeout(context.Background(), time.Second*3) res, err := mr.MapReduce(generateFunc, mapFunc, reducerFunc, mr.WithContext(ctx)) //开启现成管制超时,如果超时则调用cl办法进行所有携程 go func() { time.Sleep(time.Second * 2) fmt.Println("cl") cl() }() fmt.Println(res, err)}源码剖析首先咱们先看下一整个函数的流程图,这个流程图是我本人的了解,如果有不对的中央请大家在评论区探讨。 ...

August 3, 2022 · 1 min · jiezi

关于go:Go-Context-应用场景和一种错误用法

context 利用场景Go 的 context 包,能够在咱们须要在实现一项工作,会用到多个 routine (实现子工作)时,提供一种不便的在多 routine 间管制(勾销、超时等)和传递一些跟工作相干的信息的编程办法。 一项工作会启动多个 routine 实现。须要管制和同步多个 routine 的操作。链式的在启动的 routine 时传递和工作相干的一些可选信息。举一个例子,这里咱们提供了一个服务,每一次调用,它提供三个性能:吃饭、睡觉和打豆豆。调用者通过设置各种参数管制3个操作的工夫或次数,同时开始执行这些操作,并且能够在执行过程中随时终止。 首先,咱们定义一下吃饭睡觉打豆豆服务的数据结构。 // DSB represents dining, sleeping and beating Doudou and// parameters associated with such behaviours.type DSB struct { ateAmount int sleptDuration time.Duration beatSec int}而后提供一个 Do 函数执行咱们设置的操作。 func (dsb *DSB) Do(ctx context.Context) { go dsb.Dining(ctx) go dsb.Sleep(ctx) // Limit beating for 3 seconds to prevent a serious hurt on Doudou. beatCtx, cancelF := context.WithTimeout(ctx, time.Second*3) defer cancelF() go dsb.BeatDoudou(beatCtx) // ...}具体的执行某一个操作的办法大略是这样的:会每隔1秒执行一次,直至实现或者被 cancel。 ...

August 3, 2022 · 4 min · jiezi

关于go:初窥门径代码起手Go-lang118入门精炼教程由白丁入鸿儒首次运行golang程序EP01

前文再续,书接上回,前一篇:兔起鹘落全端涵盖,Go lang1.18入门精炼教程,由白丁入鸿儒,全平台(Sublime 4)Go lang开发环境搭建EP00,咱们搭建起了Go lang1.18的开发运行环境,接着就能够运行第一个Go lang1.18程序了,让咱们整装待发,开启Go lang1.18的处女航。 首次运行关上Sublime 4,在任意目录下新建test.go文件: package main // 申明 main 包 import "fmt" // 导入 fmt 包,打印字符串时须要用到 func main() { // 申明 main 主函数入口 fmt.Println("hello Go lang 1.18") // 打印 字符串}随后按快捷键组合 control + b 运行程序 (Mac平台应用cmd + b) 程序返回: > Environment: > GOPATH=C:/Go > Directory: C:\Users\liuyue\www\tornado6 > Command: C:/Go/bin\go.exe run -v C:\Users\liuyue\www\tornado6\test.go > Output: command-line-arguments hello go1.18 > Elapsed: 3.070s > Result: Success和Python或者Ruby这些解释型语言不同,Go lang和Java一样,是编译型语言,运行之前须要编译成可执行文件后能力执行,而 go run命令会编译源码,并且间接执行源码的 main() 函数,不会在当前目录留下可执行文件。 ...

August 3, 2022 · 2 min · jiezi

关于go:从汇编看golang可变参数函数底层如何处理

引出问题网上看到一个问题,如下代码最初输入是什么,答案是抉择是 A. 18。 但解释只有一句,知识点:可变参数函数,感觉不够啊. //hello.gopackage mainimport "fmt"func hello(num ...int) { num[0] = 18}func main() { i := []int{5, 6, 7} hello(i...) fmt.Println(i[0])}A. 18B. 5C. Compilation error从汇编解读$ go tool compile -S -N -l hello.go > 1.txt第10行: i := []int{5, 6, 7} 第11行: hello(i...) "".hello STEXT nosplit size=70 args=0x18 locals=0x18 funcid=0x0 //hello函数应用了调用方的AX、BX、CX结构出一个新的slice 0x000e 00014 (hello.go:5) MOVQ AX, "".num+32(SP) 0x0013 00019 (hello.go:5) MOVQ BX, "".num+40(SP) 0x0018 00024 (hello.go:5) MOVQ CX, "".num+48(SP)"".main STEXT size=438 args=0x0 locals=0xd0 funcid=0x0 //因为 slice i 须要的存储空间没有内存逃逸行为,所以能够间接在栈中分配内存 //先创立slice须要的底层数组,以下3行是清空操作 //底层数组的地址为 [SP+32, SP+56) 0x0026 00038 (hello.go:10) MOVQ $0, ""..autotmp_3+32(SP) //[SP+32, SP+40)清0 0x002f 00047 (hello.go:10) LEAQ ""..autotmp_3+40(SP), DX //DX=SP+40 0x0034 00052 (hello.go:10) MOVUPS X15, (DX) //X15没找到在哪,应该是个0;给DX所指向地址开始的16个字节赋0;即[SP+40, SP+56)清0 // 底层数组的地址赋值给AX,以及地址为SP+72的内存 0x0038 00056 (hello.go:10) LEAQ ""..autotmp_3+32(SP), AX 0x003d 00061 (hello.go:10) MOVQ AX, ""..autotmp_2+72(SP) 0x0042 00066 (hello.go:10) TESTB AL, (AX) //以下一段在给底层数组每个单元赋值,5、6、7 0x0044 00068 (hello.go:10) MOVQ $5, ""..autotmp_3+32(SP) 0x004d 00077 (hello.go:10) TESTB AL, (AX) 0x004f 00079 (hello.go:10) MOVQ $6, ""..autotmp_3+40(SP) 0x0058 00088 (hello.go:10) TESTB AL, (AX) 0x005a 00090 (hello.go:10) MOVQ $7, ""..autotmp_3+48(SP) 0x0063 00099 (hello.go:10) TESTB AL, (AX) 0x0065 00101 (hello.go:10) JMP 103 //以下一段是生成slice i 0x0067 00103 (hello.go:10) MOVQ AX, "".i+96(SP) //slice对应的底层数组地址 0x006c 00108 (hello.go:10) MOVQ $3, "".i+104(SP) //slice长度 0x0075 00117 (hello.go:10) MOVQ $3, "".i+112(SP) //slice容量 //hello(num ...int)函数能够接管多个参数 //三点操作符在这里起的作用是,相当于将原有slice i拆成多个参数传递 //变成hello(5, 6, 7) //再依据这多个参数生成一个长期slice,因为没有逃逸,也是在以后栈中创立 //另,golang编译阶段应该有判断,因为传入应用了三点操作符 //所以新的长期slice间接利用了已有slice的底层数组 //hello函数须要调用到的变量 AX(slice底层数组地址),BX(slice大小),CX(slice容量) //因为AX曾经是了,以下是解决BX和CX 0x007e 00126 (hello.go:11) MOVL $3, BX 0x0083 00131 (hello.go:11) MOVQ BX, CX 0x0086 00134 (hello.go:11) PCDATA $1, $1 0x0086 00134 (hello.go:11) CALL "".hello(SB)以下是将第11行改为hello(5, 6, 7)后的局部编译后果 ...

August 3, 2022 · 2 min · jiezi

关于go:兔起鹘落全端涵盖Go-lang118入门精炼教程由白丁入鸿儒Sublime-4-Go-lang开发环境搭建EP00

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_222 Go lang,为并发而生的动态语言,源于C语言又不拘泥于性能,高效却不流于古板,Python灵便,略输性能,Java谨严,稍逊风骚。君不见各大厂牌均纷纷应用Go lang对本人的高并发业务进行重构,原因无他,经济上行的大背景之下,性能突出、效率拉满的Go lang无疑是高并发场景下节约服务器资源的一剂灵药。 与时俱进,顺应潮流,本次咱们乘着市场的东风,在各大支流平台(Win/Mac/Linux/Docker)装置并搭建Go lang1.18的开发环境,短时间内做到可能在任何一款开发机或者服务器上输入Go lang的全副功力,如臂使指,龙飞凤舞。 Windows11平台首先来到市场占有率最高的Win11零碎,返回Go lang官网 https://go.dev/dl/ 下载win平台下的64位安装包: Microsoft Windows Windows 7 or later, Intel 64-bit processor go1.18.5.windows-amd64.msi (130MB)抉择装置目录后,间接点击装置即可。 装置结束之后,首先输出“win+R”,关上终端。而后在外面输出命令:control system。在关上的零碎信息界面中,抉择左侧菜单的“高级零碎设置”。随后在关上的“零碎属性”窗口抉择下方的“环境变量”选项。最初在关上的环境变量中,查看零碎是否将Go lang的装置目录"c:/go/bin"配置到了环境变量里,如果曾经配置了,在终端中键入命令: go version零碎返回: C:\Users\liuyue>go version go version go1.18.5 windows/amd64阐明Go lang1.18版本曾经在零碎中装置胜利。 Mac平台接着来到Mac零碎,Mac零碎个别会蕴含两套架构,别离是:搭载Intel芯片的x86架构零碎,和搭载M系列芯片的ARM架构零碎。 首先关上终端,键入如下命令: uname -m如果返回: arm64阐明是ARM架构零碎,反之: x86则是Intel芯片的x86架构零碎。 返回Go lang官网 https://go.dev/dl/ ARM架构零碎下载: Apple macOS (ARM64) macOS 11 or later, Apple 64-bit processor go1.18.5.darwin-arm64.pkg (132MB)X86架构零碎下载: Apple macOS (x86-64) macOS 10.13 or later, Intel 64-bit processor go1.18.5.darwin-amd64.pkg (138MB)下载之后,双击进行装置即可。 ...

August 2, 2022 · 3 min · jiezi

关于go:Go生成图片水印demo既然比PHP慢一倍

闲聊这个打水印的 demo 其实曾经实现许久,始终没有总结总结,有空填了一下本人的坑吧,也让本人温习温习。 背景公司是做图形设计资源站点,详情、搜寻页面都须要提供预览图片,图片都是蕴含公司的水印的图片,水印图片独自存储。当初公司须要更换水印图,所以要获取全副的原图,打上新水印,再替换现有的图片。 计划公司次要是 PHP 开发, 原本是打算用 Laravel 的 command 脚本实现的,但想到过后团队也是有动向转 Go 方向并且Go在有协程的加持,能够开多个协程来执行打水印这部分工作,所以最终采纳了 Go 语言来实现这个需要,算是一个的新的尝试。 实现整体流程是:遍历数据库数据->获取原图信息->下载原图->生成水印->上传水印图->更新数据库水印图片,本文次要叙述生成水印此步骤,因为这一块与 PHP 的实现上略有不同,在 Go 上可应用协程并发解决,而 PHP 只能单个解决。 Go实现go version go1.17.7 darwin/arm64同步同步执行流程与 PHP 一样,比照一下两者效率 main.go // 同步func syncGen() { startT := time.Now() // 关上水印图 water, err := pkg.OpenPngImage("./test_water.png") if err != nil { log.Fatal(err) } // 这个循环是遍历原图 imgPath := "./test.png" for i := 1; i <= num; i++ { id := i + 1000 // 模仿 id if err = pkg.Generate(imgPath, id, water); err != nil { log.Println("水印图生成失败,id=" + strconv.Itoa(i)) } } // 计算耗时 tc := time.Since(startT) fmt.Printf("同步执行工夫 = %v\n", tc)}go run main.go -n 1水印图:1 张同步执行工夫 = 109.644375ms1632*874 JPEG(24位色彩) 78.87kbPHP实现PHP 7.4.28 (cli)长期写了个 PHP 版本的同性能demo ...

August 2, 2022 · 2 min · jiezi

关于go:golang密文存储

需要加密存储用户数据,实现即便数据库泄露,也能保障用户数据的平安。 思路应用AES解决一般数据。应用Argon2解决非凡数据。 以加密后是否须要解密为规范辨别:加密后须要解密的,为一般数据(手机号、邮箱)。反之,为非凡数据(登录明码)。实现AES解决一般数据AES,Advanced Encryption Standard,高级加密规范。 // AES key,16、24或者32位,顺次对应AES-128、AES-192和AES-256。const key = "1234567887654321"// AES加密func AESEncrypt(plainText []byte) ([]byte, error) { block, err := aes.NewCipher([]byte(key)) // 应用AES key生成cipher.Block接口 if err != nil { return nil, err } plainText = pkcs5Append(plainText, block.BlockSize()) // 填充最初一个分组的数据 blockMode := cipher.NewCBCEncrypter(block, ([]byte(key))[:block.BlockSize()]) // 生成BlockMode接口 cipherText := plainText blockMode.CryptBlocks(cipherText, plainText) // 加密 return cipherText, nil}// AES解密func AESDecrypt(cipherText []byte) ([]byte, error) { block, err := aes.NewCipher([]byte(key)) // 应用AES key生成cipher.Block接口 if err != nil { return nil, err } blockMode := cipher.NewCBCEncrypter(block, ([]byte(key))[:block.BlockSize()]) // 生成BlockMode接口 plainText := cipherText blockMode.CryptBlocks(plainText, cipherText) // 解密 plainText = pkcs5Trim(plainText) return plainText, nil}// 应用PKCS#5算法填充最初一个分组的数据func pkcs5Append(ciphertext []byte, blockSize int) []byte { padding := blockSize - (len(ciphertext) % blockSize) // 计算最初一个分组缺多少个字节 padText := bytes.Repeat([]byte{byte(padding)}, padding) // 创立一个大小为padding的切片, 每个字节的值为padding newText := append(ciphertext, padText...) // 将padText增加到原始数据的后边, 将最初一个分组短少的字节数补齐 return newText}// 删除填充的数据func pkcs5Trim(origData []byte) []byte { length := len(origData) // 计算数据的总长度 number := int(origData[length-1]) // 依据填充的字节值得到填充的次数 return origData[:(length - number)] // 将尾部填充的number个字节去掉}Argon2解决非凡数据Argon2,明码散列比赛冠军算法,是比bcrypt、scrypt更牢靠的明码散列算法。 ...

August 1, 2022 · 1 min · jiezi

关于go:if-err-nil-太烦Go-创始人教你如何对错误进行编程

大家好,我是煎鱼。 前段时间我分享了一篇文章《10+ 条 Go 官网谚语,你晓得几条?》,引发了许多小伙伴的探讨。其中有一条 “Errors are values”,大家在是 “谬误是值” 还是 “谬误就是价值” 中重复横跳,纠结不易。 其实说这句话的 Rob Pike,他用一篇文章《Errors are values》诠释了这句谚语的意思,到底是什么? 明天煎鱼和大家一起学习,以下的 “我” 均代表 Rob Pike。 背景Go 程序员,尤其是那些刚接触该语言的程序员,常常探讨的一个问题是如何处理错误。对于以下代码片段呈现的次数,谈话常常变成悲叹(各大平台吐槽、批评十分多,认为设计的不好)。 如下代码: if err != nil { return err}扫描代码片段咱们最近扫描了咱们能找到的所有 Go 开源我的项目,发现这个代码片段只在每一两页呈现一次,比一些人认为的要少。 尽管如此,如果人们依然认为必须常常输出如下代码: if err != nil那么肯定有什么中央出了问题,而显著的指标就是 Go 语言自身(说设计的不好?)。 谬误的了解显然这是可怜的,误导的,而且很容易纠正。兴许当初的状况是,刚接触 Go 的程序员会问:"如何处理错误?",学习这种模式,而后就此打住。 在其余语言中,人们可能会应用 try-catch 块或其余相似机制来处理错误。因而,程序员认为,当我在以前的语言中会应用 try-catch 时,我在 Go 中只需输出 if err != nil。 随着工夫的推移,Go 代码中收集了许多这样的片段,后果感觉很蠢笨。 谬误是值不论这种解释是否适合,很显著,这些 Go 程序员错过了对于谬误的一个基本点:谬误是值(Errors are values)。 值能够被编程,既然谬误是值,那么谬误也能够被编程。 当然,波及谬误值的常见语句是测试它是否为 nil,然而还有有数其余事件能够用谬误值做,并且利用其中一些其余事件能够使您的程序更好,打消很多样板。 如果应用死记硬背的 if 语句查看每个谬误,就会呈现这种状况(也就是 if err != nil 到处都是的状况)。 ...

August 1, 2022 · 2 min · jiezi

关于go:用位运算为你的程序加速

前言最近在继续优化之前编写的 JSON 解析库 xjson,次要是两个方面的优化。 第一个是反对将一个 JSONObject 对象输入为 JSON 字符串。 这点在上个版本中只是利用自带的 Print 函数打印数据: func TestJson4(t *testing.T) { str := `{"people":{"name":{"first":"bob"}}}` first := xjson.Get(str, "people.name.first") assert.Equal(t, first.String(), "bob") get := xjson.Get(str, "people") fmt.Println(get.String()) //assert.Equal(t, get.String(),`{"name":{"first":"bob"}}`)}Output: map[name:map[first:bob]]<!--more--> 本次优化之后便能间接输入 JSON 字符串了: 实现过程也很简略,只须要递归遍历 object 中的数据,而后拼接字符串即可,外围代码如下: func (r Result) String() string { switch r.Token { case String: return fmt.Sprint(r.object) case Bool: return fmt.Sprint(r.object) case Number: i, _ := strconv.Atoi(fmt.Sprint(r.object)) return fmt.Sprintf("%d", i) case Float: i, _ := strconv.ParseFloat(fmt.Sprint(r.object), 64) return fmt.Sprintf("%f", i) case JSONObject: return object2JSONString(r.object) case ArrayObject: return object2JSONString(r.Array()) default: return "" }} ...

August 1, 2022 · 1 min · jiezi

关于go:go源码分析map全网最详细

map一、简略构造map类型的变量实质上是一个hmap类型的指针,键值对通过哈希表来贮存。如下图: 二、哈希表的设计1、构造hash表首先有一段贮存贮存数据的间断空间,咱们将数据存到这段间断的空间(能够把它当组成一个数组)外面,如下图所示,把key、value以及key的hash值存到间断的空间外面 2、寻址而后就是以后的key-value具体要存到哪一个地位呢?当初支流的通常有两种办法: 1、取模运算:hash % m 2、位运算:hash&(m-1) 咱们都晓得位运算必定是更加的高效,然而必须得限度m为2的整数幂。golang外面采纳了幂运算的办法来寻址 3、hash抵触当咱们两个key产生hash抵触了怎么解决呢?咱们也介绍两种的办法 1、拉链法:这种办法会把产生hash抵触的key-value数据用链表的形式把数据组织起来。如下图所示,当产生hash抵触的时候,前面插入的数据会链接到发生冲突的数据前面 2、凋谢地址法:比方下图,咱们编号0的地位曾经被占了,那么咱们就把数据放在编号1的地位,如果编号1的地位也被占了,由此类推,咱们持续寻址,直到找到闲暇的中央。 当咱们去查找数据的时候,咱们先会查找0地位,如果不是咱们查找的key,会持续向下查找,晓得查找到最初的地位,很显然,这种办法不适宜负载因子(前面会介绍)过大的状况 下面两种办法比照:拉链法绝对于查找数据比拟敌对,查找的次数不会太多。凋谢地址法则不会产生不间断的内存空间,每次申请的都是一块间断的内存空间。在golang中,采纳了相似于拉链法,为什么说相似呢?前面会详细分析一下map的数据结构。 4、扩容当咱们的数据曾经远远超过8个,采纳拉链法,那么hash表就会进化成链表。开发地址法就更不行了。这时候咱们就会波及到扩容的问题。扩容咱们次要搞清楚两个问题就行了:何时扩容 、怎么扩容 何时扩容 还记得咱们上文提到的负载因子吗?负载因子就是来标识何时扩容的一个参数。它是哈希表中存储的键值对数量和桶数量的比值,通常须要设定一个触发扩容的最大负载因子 loadFactor = keyCount / bucketCount咱们假如咱们的负载因子是50%,当咱们来了一个新的key12的时候,就会触发扩容 怎么扩容 咱们间接的想法是,当达到负载因子的时候,间接把buckets的容量翻倍。而后把数据都copy到新的地址空间去。如下所示 这么迁徙会有个问题。当旧桶的数据十分多的时候呢?这时候迁徙数据就会占用大量工夫,影响咱们主程序。所以简直在所有的语言中,都会采纳渐进式扩容。 这种形式下,旧桶里的键值对是分屡次挪到新桶里的,能够在触发扩容后,先调配新桶,而后标记以后哈希表正在扩容,并在哈希表的读写操作中判断若在扩容中,则迁徙一部分键值对到新桶里,这样能够把扩容耗费的工夫扩散到屡次操作中。 好了,下面咱们大略介绍了hash表的一些个性和问题,接下来咱们再介绍一下golang中的map长什么样子。 三、map的数据结构图解构造map底层的哈希表通过与运算的形式抉择桶,所以hmap中并不间接记录桶的个数,而是记录这个数目是2的多少次幂。上面咱们先看看map应用的桶长什么样子。咱们先看看之前的map根本结构图,晓得golang中一个桶其实就是一个bmap。 下图是一个bmap的数据结构。咱们能够看到bmap其实是一段间断内存空间。 为了内存应用更加紧凑,8个键放一起,8个值放一起。对应每个key只保留其哈希值的高8位(tophash)。而每个键值对的tophash、key和value的索引程序一一对应。 能够看到这个其实和咱们下面说的拉链法比拟类似,如果产生hash抵触的时候,会在bmap中向后写入,这样既保证了查找次数较少,又能保障内存比拟间断。8个存满了怎么办?为了缩小扩容次数,这里引入了溢出桶(overflow)。溢出桶的内存布局与惯例桶雷同。如果哈希表要调配的桶的数目大于2^4,就会预调配2^(B-4)个溢出桶备用。这些惯例桶和溢出桶在内存中是间断的,只是前2^B个用作惯例桶,前面的用作溢出桶。 源码剖析上面咱们具体来看看源码: type hmap struct { count int //map中值的数量 flags uint8 //动作标识(比方正在写数据) B uint8 // 惯例桶个数等于2^B noverflow uint16 // 溢出桶数量 hash0 uint32 // hash 种子 buckets unsafe.Pointer //桶的指针,指向的是 2^B 个bmap oldbuckets unsafe.Pointer //旧桶的指针(扩容时应用) nevacuate uintptr //扩容时迁徙的地位 extra *mapextra // 所有溢出桶指针}type mapextra struct { overflow *[]*bmap //曾经用到的溢出桶 oldoverflow *[]*bmap //渐进式扩容时,保留旧桶用到的溢出桶 nextOverflow *bmap //下一个尚未应用的溢出桶}type bmap struct { tophash [bucketCnt]uint8 //存储tophash的值}能够看到如果以后桶存满了当前,查看hmap.extra.nextoverflow还有可用的溢出桶,就在这个桶前面链上这个溢出桶,而后持续往这个溢出桶里 ...

July 31, 2022 · 6 min · jiezi

关于go:Go十大常见错误第3篇Go指针的性能问题和内存逃逸

前言这是Go十大常见谬误系列的第3篇:Go指针的性能问题和内存逃逸。素材来源于Go布道者,现Docker公司资深工程师Teiva Harsanyi。 本文波及的源代码全副开源在:Go十大常见谬误源代码,欢送大家关注公众号,及时获取本系列最新更新。 场景咱们晓得,函数参数和返回值能够应用变量或者指向变量的指针。 Go初学者容易有一种误会: 认为函数参数和返回值如果应用变量的值会对整个变量做拷贝,速度慢认为函数参数和返回值如果应用指针类型,只须要拷贝内存地址,速度更快但事实真的是这样么?咱们能够看下这段代码 this example,做性能测试的后果如下: $ go test -bench .goos: darwingoarch: amd64pkg: pointercpu: Intel(R) Core(TM) i5-5250U CPU @ 1.60GHzBenchmarkByPointer-4 6473781 178.2 ns/opBenchmarkByValue-4 21760696 47.11 ns/opPASSok pointer 2.894s能够看出,参数和返回值都用指针的函数比参数和返回值都用变量值的函数慢很多,前者的耗时是后者的4倍。 初学者看到这个,可能会感觉有点反直觉,为什么会这样呢? 这和Go对stack(栈)和heap(堆)的内存治理有关系,变量调配在stack上还是heap上,对性能是会有影响的。 stack上分配内存效率比heap更高,而且stack上调配的内存不必做GC,超出了作用域,就主动回收内存。放在heap上的内存,须要由GC来做内存回收,而且容易产生内存碎片。编译器在编译期决定变量调配在stack还是heap上,须要做逃逸剖析(escape analysis),逃逸剖析在编译阶段就实现了。什么是逃逸剖析呢? Go编译器解析源代码,决定哪些变量调配在stack内存空间,哪些变量调配在heap内存空间的过程就叫做逃逸剖析,属于Go代码编译的一个分析阶段。 通过逃逸剖析,编译器会尽可能把能调配在栈上的对象调配在栈上,防止堆内存频繁GC垃圾回收带来的零碎开销,影响程序性能。 案例1咱们看上面的代码:其中构造体foo的能够参考 this example。 func getFooValue() foo { var result foo // Do something return result}变量result定义的时候会在这个goroutine的stack上调配result的内存空间。 当函数返回时,getFooValue的调用方如果有接管返回值,那result的值会被拷贝给对应的接管变量。 stack上变量result的内存空间会被开释(标记为不可用,不能再被拜访,除非这块空间再次被调配给其它变量)。 留神:本案例的构造体foo占用的内存空间比拟小,约0.3KB,goroutine的stack空间足够存储,如果foo占用的空间过大,在stack里存储不了,就会分配内存到heap上。 案例2咱们看上面的代码: func getFooPointer() *foo { var result foo // Do something return &result}函数getFooPointer因为返回的是一个指针,如果变量result调配在stack上,那函数返回后,result的内存空间会被开释,就会导致承受函数返回值的变量无法访问本来result的内存空间,成为一个悬浮指针(dangling pointer)。 所以这种状况会产生内存逃逸,result会调配在heap上,而不是stack上。 ...

July 30, 2022 · 2 min · jiezi

关于go:go源码阅读sortSearchInts与Search

先上源码在做leetcode35搜寻插入地位的时候,偶然间,我想起来了sort.SearchInts函数 于是我棘手点开了SearchInts的源码 出其不意的,这个函数的代码只有一行 再次点进search函数的源码 能够看到 通过浏览发现 这是一个二分查找的模板, 传入的参数为 数组的长度n,以及,一个返回为bool的函数值 对0和n进行操作获得两头值h为了避免溢出,在求平均值时应用无符号数uint失去双倍的最大示意数 之后,依据函数值的断定后果抉择区间并再次进行二分查找,直至完结 这里巧用函数值作为参数,让所有须要应用二分查找模板的人都能调用这个模板,并重写适宜本人的函数值f作为二分查找的断定条件 可见,函数值是go中一个微妙的设计,对于函数值的具体介绍,能够看go圣经中的函数值局部https://books.studygolang.com... 于是,咱们从新回到sort.SearchInts函数,他的f断定条件为 切片的第i个数是否大于参数x天然,二分查找的后果就是 在参数a这个切片中,寻找x这个数切片中如果有这个数,则返回他的索引如果找不到这个数,则返回第一个大于x的的数的索引

July 29, 2022 · 1 min · jiezi

关于go:go源码阅读-stringsCompare-字符串比较

一、介绍在编程中,咱们须要常常的进行字符串比拟咱们次要用4中比拟操作符 == 相等查看!= 不等于>= 大于或等于 (>大于)<= 小于或等于 (<小于)

July 29, 2022 · 1 min · jiezi

关于go:两个-go-struct-比较

两个 go struct 比拟

July 29, 2022 · 1 min · jiezi

关于go:golang从入门到入土三分支循环结构

代码地址 能够依据git log查看 package mainimport ( "bufio" "fmt" "io/ioutil" "os" "strconv" "time")func main() { const filenmae = "abc.txt" contents, err := ioutil.ReadFile(filenmae) // 写法一 if err != nil { fmt.Println(err) } else { fmt.Printf("%s", contents) } // 写法二 if语句能够写表达式, if语句能够赋值,这里的赋值的作用域只在if语句只内 if contents, err = ioutil.ReadFile(filenmae); err != nil { fmt.Println(err) } else { fmt.Printf("%s\n", contents) } // fmt.Println( // converToBin(0), // converToBin(2), // converToBin(5), // ) readFileAsLine(filename)}// if语句func bounded(v int) int { if v > 100 { return 100 } else if v < 0 { return 0 } else { return v }}// switch 语句func eval(a, b int, op string) int { var result int // switch 语句不必加break,默认有break,如果须要不break,就应用fallthrough 让他继续执行 // switch 前面能够没有表达式,在case里写条件判断 switch op { case "+": result = a + b case "-": result = a - b case "*": result = a * b case "/": result = a / b default: panic("参数谬误") } switch { case a > 0: fmt.Println("a") case a < 0: fmt.Println("b") default: fmt.Println("c") } return result}// for 语句/** * 将10进制转换成2进制 * 循环/2 取余 直到商变为9 ,而后倒转 */func converToBin(a int) string { // for循环没有括号 // for 循环能够没有出事表达式,没有判断表达式,没有递增表达式 var result string if a == 0 { return strconv.Itoa(a) } for ; a > 0; a /= 2 { lsb := a % 2 result = strconv.Itoa(lsb) + result } return result}var filename string = "abc.txt"func readFileAsLine(filename string) string { file, err := os.Open(filename) if err != nil { panic(err) } scanner := bufio.NewScanner(file) for scanner.Scan() { fmt.Println(scanner.Text()) time.Sleep(1 * time.Second) } return ""}

July 28, 2022 · 2 min · jiezi

关于go:go源码分析切片

slice一、构造组成切片实质上是一个构造体slice,他的属性由上面三局部组成: array:元素存哪里len:曾经存了多少cap:容量是多少type slice struct { array unsafe.Pointer //数组的指针 len int //切片长度 cap int //切片容量} 举个例子咱们都晓得,go语言的办法传参数都是值传递。 因为切片类型是一个构造体,所以当传到change办法的时候,形参arr是arrOri一份正本。然而因为属性array是一个指针,所以扭转arr的值,也会影响到arrOri func main() { arrOri := []string{"0", "1", "2"} change(arrOri) fmt.Println(arrOri[0])}func change(arr []string) { if len(arr) > 0 { arr[0] = "test0" }}//output:test0二、append产生了什么?通过下面的例子咱们晓得,如果某个办法扭转的切片某个地位的值,也会影响到原切片。 上面咱们再看一下这个例子,为什么最初输入是0,而不是test0呢?接下来咱们持续来聊聊扩容 func main() { arrOri := []string{"0", "1", "2","3"} change2(arrOri) fmt.Println(arrOri[0])}func change2(arr []string) { arr = append(arr, "4") if len(arr) > 0 { arr[0] = "test0" }}//output:0咱们最开始申明切片arrOri的时候给了4个元素,那切片的初始容量为4,array如下图的下面的数组。 但当咱们增加一个元素的时候,原先的数组的长度曾经不够咱们减少元素。 所以须要申明一个新的更长数组,把老数组的数据复制到新的数组中去,而后追加咱们须要增加的元素,最初把切片的属性array的指针指向新的数组。 所以arrOri的array属性指向的是老数组,而arr的array属性指向的是新的数组,扭转arr的值不会影响到arrOri的值。 上面是append是的源码解析: ...

July 28, 2022 · 2 min · jiezi

关于go:服务发现原理分析与源码解读

在微服务架构中,有许多绕不开的技术话题。比方服务发现、负载平衡、指标监控、链路追踪,以及服务治理相干的超时管制、熔断、降级、限流等,还有RPC框架。这些都是微服务架构的根底,只有打牢这些根底,才敢说对微服务是有了一点了解,出门也好意思和他人打招呼了,被人发问的时候也能娓娓而谈了,线上出了问题往往也能寻根溯源心田不慌了,旁边的女同事小芳看着你的时候也是满眼的小可爱了。 在《微服务实际》公众号,之前写了《go-zero微服务实战系列》的系列文章,这个系列的文章更多的是偏差业务性能和高并发下的服务优化等。自己程度无限,不免有写的有余的中央,但也仍然失去了大家的反对与激励,倍感荣幸,所以决定趁热打铁,乘胜追击,持续给大家输入干货。 《彻底搞懂系列》会基于 go-zero v1.3.5 和 grpc-go v1.47.0 和大家一起学习微服务架构的方方面面,次要模式是实践+源码+案例,如果工夫容许也可能会加上配套视频。 本篇文章作为该系列的第一篇,会先介绍绝对比较简单的服务发现相干内容。 撸袖子开搞,奥利给!!! 服务发现为什么在微服务架构中,须要引入服务发现呢?实质上,服务发现的目标是解耦程序对服务具体位置的依赖,对于微服务架构来说,服务发现不是可选的,而是必须的。因为在生产环境中服务提供方都是以集群的形式对外提供服务,集群中服务的IP随时都可能发生变化,比方服务重启,公布,扩缩容等,因而咱们须要用一本“通讯录”及时获取到对应的服务节点,这个获取的过程其实就是“服务发现”。 要了解服务发现,须要晓得服务发现解决了如下三个问题: 服务的注册(Service Registration) 当服务启动的时候,应该通过某种模式(比方调用API、产生上线事件音讯、在Etcd中记录、存数据库等等)把本人(服务)的信息告诉给服务注册核心,这个过程个别是由微服务框架来实现,业务代码无感知。 服务的保护(Service Maintaining) 只管在微服务框架中通常都提供下线机制,但并没有方法保障每次服务都能优雅下线(Graceful Shutdown),而不是因为宕机、断网等起因忽然失联,所以,在微服务框架中就必须要尽可能的保障保护的服务列表的正确性,以防止拜访不可用服务节点的难堪。 服务的发现(Service Discovery) 这里所说的发现是广义的,它特指消费者从微服务框架(服务发现模块)中,把一个服务标识(个别是服务名)转换为服务理论地位(个别是ip地址)的过程。这个过程(可能是调用API,监听Etcd,查询数据库等)业务代码无感知。 服务发现有两种模式,别离是服务端服务发现和客户端服务发现,上面别离进行介绍。 服务端服务发现对于服务端服务发现来说,服务调用方无需关注服务发现的具体细节,只须要晓得服务的DNS域名即可,反对不同语言的接入,对基础设施来说,须要专门反对负载均衡器,对于申请链路来说多了一次网络跳转,可能会有性能损耗。也能够把咱们比拟相熟的 nginx 反向代理了解为服务端服务发现。 客户端服务发现对于客户端服务发现来说,因为客户端和服务端采纳了直连的形式,比服务端服务发现少了一次网络跳转,对于服务调用方来说须要内置负载均衡器,不同的语言须要各自实现。 对于微服务架构来说,咱们冀望的是去中心化依赖,中心化的依赖会让架构变得复杂,当呈现问题的时候也会让整个排查链路变得繁琐,所以在 go-zero 中采纳的是客户端服务发现的模式。 gRPC的服务发现gRPC提供了自定义Resolver的能力来实现服务发现,通过 Register办法来进行注册自定义的Resolver,自定义的Resolver须要实现Builder接口,定义如下: grpc-go/resolver/resolver.go:261 type Builder interface { Build(target Target, cc ClientConn, opts BuildOptions) (Resolver, error) Scheme() string}先说下 Scheme() 办法的作用,该办法返回一个stirng。注册的 Resolver 会被保留在一个全局的变量m中,m是一个map,这个map的key即为 Scheme() 办法返回的字符串。也就是多个Resolver是通过Scheme来进行辨别的,所以咱们定义 Resolver 的时候 Scheme 不要反复,否则 Resolver 就会被笼罩。 grpc-go/resolver/resolver.go:49 func Register(b Builder) { m[b.Scheme()] = b}再来看下Build办法,Build办法有三个参数,还有Resolver返回值,乍一看不晓得这些参数是干嘛的,遇到这种状况该怎么办呢?其实也很简略,去源码里看一下Build办法在哪里被调用的,就晓得传入的参数是哪里来的,是什么含意了。 ...

July 28, 2022 · 6 min · jiezi

关于go:Go-程序太大了能要个延迟初始化不

大家好,我是煎鱼。 在公司的一直倒退中,一开始大多是大单体,革新慢了,一个仓库会有应用几十年的状况,仓库的规模根本是一直增大的过程。 影响之一就是会应用程序打包后的体积越来越大,不晓得被用哪里去了...明天要探讨的提案《proposal: language: lazy init imports to possibly import without side effects》,就与此有关。 提案背景咱们来察看一段很简略的 Go 代码,钻研钻研。如下代码: package mainimport _ "crypto/x509"func main() {}这个 Go 程序只有 3 行代码,看起来就没有任何货色。实际上是这样吗? 咱们能够执行以下命令看看初始化过程: $ go build --ldflags=--dumpdep main.go 2>&1 | grep inittask输入后果: runtime.main -> runtime..inittaskruntime.main -> main..inittaskmain..inittask -> crypto/x509..inittaskcrypto/x509..inittask -> bytes..inittaskcrypto/x509..inittask -> crypto/sha256..inittaskcrypto/x509..inittask -> encoding/pem..inittaskcrypto/x509..inittask -> errors..inittaskcrypto/x509..inittask -> sync..inittaskcrypto/x509..inittask -> crypto/aes..inittaskcrypto/x509..inittask -> crypto/cipher..inittaskcrypto/x509..inittask -> crypto/des..inittask...context..inittask -> context.init.0vendor/golang.org/x/net/dns/dnsmessage..inittask -> vendor/golang.org/x/net/dns/dnsmessage.initvendor/golang.org/x/net/route..inittask -> vendor/golang.org/x/net/route.initvendor/golang.org/x/net/route..inittask -> vendor/golang.org/x/net/route.init.0...这段程序其实初始化了超级多的软件包(规范库、第三方包等)。使得包的的大小从规范的 1.3 MB 变成了 2.3 MB。 ...

July 27, 2022 · 1 min · jiezi

关于go:go-stringsToLower-原理解析

一、ASCII 介绍英语的字母大小写转化,是咱们常遇到的字符串解决状况。 一、go中解决字符串 转化小写 func ToLower(s string) string { b := strings.Builder{} b.Grow(len(s)) for i := 0; i < len(s); i++ { c := s[i] if 'A' <= c && c <= 'Z' { c += 'a' - 'A' } b.WriteByte(c) } return b.String()}测试函数: import "testing"func TestToLower(t *testing.T) { type args struct { s string } tests := []struct { name string args args want string }{ {"1", args{s: "A"}, "a"}, {"1", args{s: "Aa"}, "aa"}, {"1", args{s: "Aa0"}, "aa0"}, {"1", args{s: ")A_$"}, ")a_$"}, {"1", args{s: "0000"}, "0000"}, {"1", args{s: "哈哈a"}, "哈哈a"}, {"1", args{s: "哈哈A啊啊"}, "哈哈a啊啊"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ToLower(tt.args.s); got != tt.want { t.Errorf("ToLower() = %v, want %v", got, tt.want) } }) }}

July 27, 2022 · 1 min · jiezi

关于go:聚合网盘程序Alist宝塔面板安装部署教程网盘挂载程序

简介Alist是一款开源的网盘代理程序,简略来说就是将市面上罕用的网盘的文件全副挂载到这款程序当中,实现一个网页能够查看阿里云盘、百度网盘、蓝奏云盘、天翼云盘等。后端基于golang的gin框架,前端应用vue和ant design开发。 搭建本文将应用Linux服务器宝塔面板进行装置Alist并运行。 一、创立网站宝塔面板点击网站->增加站点->增加域名(端口号5244) 二、进入网站目录下载Alist 点击左侧的文件->终端 在终端输出以下命令进行装置(其中alist.xxx.com是你创立的网站的目录名) curl -fsSL "https://nn.ci/alist.sh" | bash -s install /www/wwwroot/alist.xxx.com 装置实现就会弹出初始密码及一些常用命令和拜访形式。 拜访Alist拜访你的服务器IP+端口号即可进入Alist后盾,例如192.168.0.1:5244,或者解析域名后,拜访域名+端口号也能够进入。 这里的明码就是初始密码,登录后,能够批改明码。 增加网盘在Alist后盾,点击账号,增加一个网盘,我这里以Lanzou云盘进行演示。 将一些简略的配置填完后,这里重要的就是这个cookie,想方法获取到cookie就能够获取到你蓝奏云盘所有文件了。 获取蓝奏云盘cookie的办法:拜访 http://lanzou.com 登录你的账号,而后F12关上开发者工具,点击NetWork(有些浏览器是网络),而后点击mydisk.php就能够看到cookie了,全副复制过来保留即可。 查看Alist首页目录拜访你的域名+端口即可进入首页。 作者Author:TANKINGWechat:sansure2016

July 26, 2022 · 1 min · jiezi

关于go:generic-type

wildcard captureThe compiler doesn't know anything about the type of elements in List<?> i, by definition of ?. Wildcard does not mean "any type;" it means "some unknown type." It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value.That's true, but as I said above: the compiler can only know – at compile time, remember – that i.get(0) returns an Object, which is the upper bound of ?. But there's no guarantee that ? is at runtime Object, so there is no way for the compiler to know that i.set(0, i.get(0)) is a safe call. It's like writing this: ...

July 26, 2022 · 1 min · jiezi

关于go:go-源码阅读-stringsBuilder-与-拼接区别

一、罕用拼接办法字符串拼接在日常开发中是很常见的需要,目前有两种广泛做法:一种是间接用 += 来拼接 s1 := "hi "s2 := "sheng"s3 := s1 + s2 // s3 == "hi sheng"s1 += s2 // s1 == "hi sheng"这是最罕用也是最简略直观的办法,不过简略是有代价的,golang的字符串是不可变类型,也就是说每一次对字符串的“原地”批改都会从新生成一个string,再把数据复制进去,这样一来将会产生很可观的性能开销,稍后的性能测试中将会看到这一点。 func TestS(t *testing.T) { s := "hello" t.Logf("%p", &s) //0xc000092350 stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))//&{18098388 5} t.Log(stringHeader.Data) s += "world" t.Logf("%p", &s) //0xc000092350 stringHeader = (*reflect.StringHeader)(unsafe.Pointer(&s))//&{824634335664 10} t.Log(stringHeader.Data)}输入: 0xc000092350&{18098388 5}0xc000092350&{824634335664 10}二、

July 25, 2022 · 1 min · jiezi

关于go:golang从入门到入土二变量类型

代码地址 能够依据git log查看 变量类型bool,string(u)int,(u)int8,(u)int16,(u)int32,(u)int64,uintptr(地址)!uintptr介绍byte,rune(相当于char类型,这里是32位的。然而不是一个字节长度,英文为一个字节,中文2-3个字节,为了应答多国语言设置)float32,float64,complex64,complex128(复数) 复数:i的平方为-1 3+4i=3的平方+4的平方取平方根为5强制类型转换 类型加上括号float 类型可能会导致数据不精确常量定义应用const标识const [类型] 变量名=值const 也能够应用括号一次定义多个常量不倡议应用全大写,因为go的大小写和作用域相干枚举类型iota 自增实现uint 无符号整型 32或64uint8uint16uint32uint64intint8...var a int8=127;fmt.Println(a+1) //输入-128 双向链表,指针向后1,就成了最开始的地位int 和 int8 类型的数字比拟会报错,类型不统一的谬误byte uint8的别名rune int32别名uintptr 无符号整形,用于寄存指针的无符号整形float32 float64complex64 32位实数和虚数complex128 64位实数和虚数//字符串len(str) + 或者fmt.Sprintf 拼接strings.Split 宰割strings.Contains 判断蕴含strings.HasPrefix 前后缀判断string.Index() string.LastIndex() 子串地位strings.Join(string,sep) 连贯//类型转换strconv 库 int8()强制转换等//下划线用法import ( _ "xxx" //只会执行包的init办法,不援用包)

July 25, 2022 · 1 min · jiezi

关于go:转载Go两种swap解析

package mainimport ( "fmt")func main() { x, y := 1, 2 fmt.Printf("x替换前的地址=%p\n",&x) fmt.Printf("y替换前的地址=%p\n",&y) swap(&x, &y) fmt.Println(x, y) fmt.Printf("x替换后的地址=%p\n",&x) fmt.Printf("y替换后的地址=%p\n",&y)}func swap(a, b *int) { fmt.Printf("a变量自身的地址=%p\n", &a) fmt.Printf("b变量自身的地址=%p\n", &b) fmt.Printf("a替换前的x赋予的地址=%p\n", a) fmt.Printf("b替换前的y赋予的地址=%p\n", b) fmt.Printf("a替换前的值=%d\n", *a) fmt.Printf("b替换前的值=%d\n", *b) *b, *a = *a, *b fmt.Printf("a变量自身的地址=%p\n", &a) fmt.Printf("b变量自身的地址=%p\n", &b) fmt.Printf("a替换后的x赋予的地址=%p\n", a) fmt.Printf("b替换后的y赋予的地址=%p\n", b) fmt.Printf("a替换后的值=%d\n", *a) fmt.Printf("b替换后的值=%d\n", *b)} 输入后果如下: x替换前的地址=0xc0000a0068y替换前的地址=0xc0000a0080a变量自身的地址=0xc0000ca020b变量自身的地址=0xc0000ca028a替换前的x赋予的地址=0xc0000a0068b替换前的y赋予的地址=0xc0000a0080a替换前的值=1b替换前的值=2a变量自身的地址=0xc0000ca020b变量自身的地址=0xc0000ca028a替换后的x赋予的地址=0xc0000a0068b替换后的y赋予的地址=0xc0000a0080a替换后的值=2b替换后的值=12 1x替换后的地址=0xc0000a0068y替换后的地址=0xc0000a0080 替换胜利。 上面将swap办法中的*b, *a = *a, *b改为b, a = a, b输入后果如下: x替换前的地址=0xc00000a0c0y替换前的地址=0xc00000a0c8a变量自身的地址=0xc000006030b变量自身的地址=0xc000006038a替换前的x赋予的地址=0xc00000a0c0b替换前的y赋予的地址=0xc00000a0c8a替换前的值=1b替换前的值=2a变量自身的地址=0xc000006030b变量自身的地址=0xc000006038a替换后的x赋予的地址=0xc00000a0c8b替换后的y赋予的地址=0xc00000a0c0a替换后的值=2b替换后的值=11 2x替换后的地址=0xc00000a0c0y替换后的地址=0xc00000a0c8 替换失败。 内存图解析 ...

July 25, 2022 · 1 min · jiezi

关于go:gomicro-pprof分析工具

pprof是golang程序性能剖析工具,go-micro基于官网pprof做了一层封装,对网络和利用封装了一套残缺的分析方法。 源码剖析profilego-micro的pprof剖析在以下包中: "github.com/micro/go-micro/v2/debug/profile""github.com/micro/go-micro/v2/debug/profile/pprof"其中profile是封装好的办法。其外部提供: type Profile interface { // Start the profiler Start() error // Stop the profiler Stop() error // Name of the profiler String() string}Start():性能监控启动 Stop():性能监控进行 还提供了自定义pprof路由名字的接口: // Name of the profilefunc Name(n string) Option { return func(o *Options) { o.Name = n }}提供一个开箱即用的profile var ( DefaultProfile Profile = new(noop))其外部实现了runtime/pprof和net/http/pprof两种场景的采样性能监控,理论应用咱们提到 实战局部理论我的项目中咱们须要本人配置一些pprof的参数,不便咱们标识是对那些利用作性能监控 runtime/pprof性能监控配置如下 import ( "github.com/micro/go-micro/v2/debug/profile" "github.com/micro/go-micro/v2/debug/profile/pprof")func PprofBoot() { pf := pprof.NewProfile( profile.Name("test"), ) pf.Start()}1.应用pprof的办法NewProfile(),改办法返回一个profile.Profile对象 2.NewProfile()反对opts ...profile.Option配置参数,目前只有批改监控前缀这个一个配置参数 3.应用Start()可间接启动 net/http/pprof采样监控 ...

July 25, 2022 · 2 min · jiezi

关于go:读书笔记-Go语言学习指南惯例模式与编程实践

Go 的并发编程go 关键字的任何返回值都会被疏忽 就像 Java 的 Thread, Java的 Thread 你须要写一堆货色,然而 go 语言你只须要写一个 gogoroutine在 go 语言外面, 启动一个 goroutine 是简略的, 简单的是: 如何取到 goroutine 的返回值如何确保 goroutine 不泄露如何优雅的敞开 goroutine如何让 goroutine 和 channel 擦出火花范式:go + chanin <-chan int, out chan<- int go 关键字配合 chan 传递出参和入参 watchout! 出参和入参都是参数, 不是间接 return 的import "fmt"func process(val int) int { fmt.Println(val) return val}func runThingConcurrently(in ***<-chan*** int, out ***chan<-*** int) { go func() { for val := range in { result := process(val) out <- result } }()}通道通道是援用类型 (什么是援用类型,除了援用类型之外,还有其余什么类型,我怎么晓得什么识货该应用什么类型?) ...

July 25, 2022 · 9 min · jiezi

关于go:Go容器化微服务系统实战

课程链接:https://www.itwangzi.cn/3459....微服务根底介绍步骤0:初窥门径 本节次要内容:本节次要内容 = 微服务 + docker + go-micro 。第一就是介绍微服务,介绍微服务偏概念多一点,原理虽干燥但也要做好心理准备,次要是解说微服务如何拆分,以及微服务里有哪些定律;第二就是docker的疾速入门以及应用。docker在微服外面占着无足轻重的作用,因为有了docker,微服务才变得容易;第三就是go-micro微服务框架的入门,go-micro微服务框架能够极大的简化微服务的开发。步骤1:小试牛刀 钻研微服务是个什么货色。以问题为导向,作为思考的切入点。【学识 = 边学边问】 带着问题来学上面的内容。问题1:是什么是微服务?问题2:为什么须要这个微服务?问题3:微服务外面DDD是什么?步骤2:庖丁解牛 问题1:是什么是微服务?咱们先来说一下什么是微服务。微服务,首先它是一种架构模式,这个架构模式是相较于单体利用来说的,相比拟咱们单体架构,微服务架构更独立,它可能独自的更新和公布,这也是微服务最大的一个特点;【请记死】在微服务外面,它外面的服务仅仅是用于某一个特定的业务性能,这就是咱们的微服务。上面咱们就用一个图来解释一下:在这里插入图片形容右边就是咱们单体利用,把咱们所有的性能还有所有的业务,比如说这个面条,咱们把所有的货色放到这一个盘子外面,它就是一个单体利用,更新和公布都是一起的,它是独立不开来的。【把鸡蛋放在同一个篮子里】微服务架构就好比左边,在一个盒子外面放了很多个甜甜圈,咱们能够把这个甜甜圈认为是咱们的功能模块,咱们一个一个的功能模块组合成了咱们叫一盒,咱们也叫它一个零碎,这个盒子就能够是咱们的电商零碎,这里的一个甜甜圈就能够看成咱们一个一个的功能模块。右边是单体利用;左边是微服的架构模式。这样了解是不是很具体化、形象化?大家本人领会一下。【你品,你细品】问题2:为什么须要这个微服务?为什么须要微服务?微服务它的逻辑比拟清晰,因为咱们后面说的相较于单体利用来说,咱们这里的微服务它是把一个一个的功能模块拆分到了咱们不同的甜甜圈里,这样就人造的造成了逻辑清晰。【一个萝卜一个坑】比如说我当初要更新一个用户模块的一个性能,咱们间接去到用户模块的那个微服务就去批改;微服务能够疾速迭代,这里的疾速迭代是相较于咱们单体利用来说的,单体利用咱们是把所有的性能放到一个盘子外面,咱们只能在同一个工夫点进行集中的测试,而后集中的上线,这会极大的升高了咱们迭代的速度。微服务是把它一个一个拆分开来,拆分成一个一个的甜甜圈,一个一个的模块能够独自的公布,这样的极大的能够晋升咱们的迭代速度,这就是咱们为什么须要一个微服务的一个重要的理由,大部分团队外面这个迭代速度占着十分重要的位置,因为公司业务需要迭代也十分的快;咱们为什么须要微服务呢?就是在咱们一个零碎外面它不仅仅是只波及到一门编程语言,比如说咱们这个零碎外面它会有咱们的AI利用,AI利用目前比拟火的语言是Python,然而咱们业务需要,业务零碎外面它基本上都是用Java写的,咱们Python和Java的交互,通常状况下要不就是通过接口,通过接口这种形式,咱们公布、包含咱们拆分,又回到了单体利用那种场景上来了。那么咱们用了微服务当前,咱们齐全能够把咱们的Java,还有咱们的Python很敌对的联合起来,【当Python的灵便遇到Java的壮实,让胶水牢牢粘住咱们的后端】 咱们用了微服务当前,这样就能够完满的屏蔽了语言的差别,这也是咱们为什么须要微服务的一个特点。那么上面咱们再来说一下微服务与DDD。DDD是什么?畛域驱动设计【Domain Driven Design】 它是一个简称,全称是畛域驱动设计。在微服务里这个畛域驱动设计是用来干嘛的?咱们在微服务的开发的过程呢,划分微服务是一个难点,也是大家常常争执的一个焦点。咱们怎么正当的去划分这个微服务,而不是一味的把微服务拆分成一个渺小的服务,不是通过咱们代码量来进行拆分,如果是仅仅通过代码行数来拆分咱们的微服务,你做到最初你会发现这是一个灾难性的决定,所以咱们要正当的拆分咱们的微服务,咱们正当拆分微服就会用到这个畛域驱动设计,上面就是着重的介绍畛域驱动设计。咱们还要说到一点就是有一个定律是康威定律,你又有疑难了,康威定律又是什么呢?康威定律就是咱们零碎的架构受制于咱们产生这个零碎组织架构,艰深一点来讲,就是你的组织架构和你的微服务拆分的这些模块一一对应,这样能力防止咱们沟通老本逐渐的减少。这个定律就是康威定律。上面咱们再来具体的说一下DDD的作用。真正决定软件架构复杂性的是设计办法,就是你软件特地简单,其实它不是技术简单,而是你的设计办法简单了,咱们这里的DDD有助于领导咱们确定零碎的边界,可能让咱们聚焦在零碎的外围元素之上。有了前两个【确定零碎边界+聚焦外围元素】就会帮忙咱们拆分零碎。这是DDD的三个次要的作用,还有一个总结的办法。真正决定软件架构复杂性的是设计办法,而不是咱们零碎自身,不是咱们技术简单,技术当然它也会有一个复杂性,然而它的复杂性是咱们通过学习,通过训练能够把握的,咱们软件的复杂性通常是因为咱们设计办法导致的。接下来介绍DDD的一些基本概念。DDD全称叫做畛域驱动设计。畛域:有范畴的界线,有边界的。【隔行如隔山】在畛域外面还有一个外围概念就是外围畛域:外围畛域代表的就是业务零碎的外围价值,还有一个通用子域,通用子域提供了咱们通用的服务,还有一个撑持子域,撑持子域就是咱们业务零碎的某一个重要的服务,这几个概念外面大家可能十分直观的能感觉到 畛域就是界线,然而外围畛域、通用子域和撑持子域又是什么货色呢?上面通过例子给大家来介绍一下。电商它是一个畛域,咱们就能够了解为它是一个大的界线,有边界的,有范畴的界线。其中的子域:有咱们的商品子域、用户子域、销售子域、订单子域等等,这是它的一个子域。外围子域:电商零碎的销售子域就是咱们的外围子域;撑持子域:就是除去销售子域以外的就是撑持子域。在电商零碎外面通用子域又是什么货色呢?通用子域就是咱们短信、邮件(用于告诉)。咱们方才举了一个电商的例子,对畛域、外围畛域、通用子域,还有撑持子域这些词汇做了简略的了解。咱们有了畛域这个概念,咱们还有一个界线上下文,界线上下文又是什么?它能够说是咱们语文中的语境的意思,比如说咱们常常说的一个段子,我想静静,第一,这个句子表白就是我想静一静的意思,然而咱们把它换一个角度,换一个语境来讲的话,静静是谁?就晓得咱们语境它很微妙。咱们这里的界线上下文也是语境的意思,只是它在DDD畛域驱动设计外面,它叫界线上下文,咱们怎么用界线上下文的形式?就是畛域+界线上下文。咱们有了畛域当前,界线上下文又有什么用?尽管界线上下文也有划分的性能,也有辨别的性能,它最次要的目标是在于管制边界,比如说我在畛域外面,比方畛域是我想静静,我要管制这个边界,我不能把语境示意成静静是谁,而是我想表白我想静一静,就是咱们要用到界线上下文。界线上下文的作用:在于如何管制边界而非如何划分边界。另外在DDD外面还有一个罕用的概念,就是畛域模型,咱们后面说了畛域、界线上下文。畛域模型对咱们软件设计是十分重要的,它是要解决问题形象的一种表白,就是你要解决什么问题,你先把它形象进去,就是畛域模型,然而畛域模型有多种形象的模式。畛域咱们能够简略的反映咱们业务上须要解决的一个问题,比方电商畛域须要解决的一个问题,咱们销的销售子域要解决销售一些问题,那么这个模型就是针对咱们该问题提出的解决方案。了解畛域模型:畛域模型是对软件系统中要解决的问题的形象表白。畛域:是咱们业务上要解决的问题。模型:是咱们针对该问题提出的解决方案。接下来咱们再来说一下这个DDD畛域的4层架构:在这里插入图片形容这个4层架构是十分经典的一个架构:Interface咱们也通常叫它User Interface【即UI,用户接口,展现给用户看的货色】,就是咱们用户的界面层,示意的是面向用户展现的一层;应用层就是示意咱们如何去接管用户,如何调配这个工作,如何让它们协调的进行单干;畛域层次要是咱们业务的状态,业务的信息以及咱们的业务规定,次要是在畛域层。基础设施层就是咱们通用的一些基础设施,比如说咱们的中间件,还有咱们的云设施等等。畛域在微服务外面是一种典型的就是咱们精简的4层架构,那么咱们在微服务外面拆分应用到的是什么呢?依据4层架构咱们再持续拆分:在这里插入图片形容持续拆分微服务外面的架构,第一,就是咱们前端的利用,前端利用可能是用Vue写的,可能是用React写的,可能是html + css + js写的,写完了当前它会调用咱们的接口,它跟后盾进行交互的时候会调用接口,调用接口的时候它会调用API网关,【为什么调用网关?因为要解决网络互通的问题,艰深的说就是能ping通】网关就是咱们的基础设施。Interface会把这些货色转发到咱们的接口层,接口层转发完了当前,它会有一个应用层,咱们会把应用层一些利用、一些逻辑的组织形式,放到咱们应用层外面,而后应用层再调用畛域服务。在畛域层外面有一些畛域的服务,咱们在畛域层进一步调用咱们的基础设施,比如说咱们的MySQL,Redis。这些调用在微服务架构外面的次要拆分下来就是这样的一个过程。后面咱们讲了微服务DDD,而后微服务是什么,还有咱们为什么须要微服务?咱们讲了那么一大堆,目标就是给大家来建设一套微服务的认知,通知大家微服务是什么?是什么晓得了当前咱们再回到微服的设计准则。在咱们设计的时候遵循一些准则,咱们在设计微服务的时候,要遵循畛域驱动设计,而不是数据驱动设计,也不是界面驱动设计。数据驱动设计是什么意思?举个例子,就是咱们一个零碎下来,咱们把模块拆分完了,而后大家就开始需要剖析,剖析完了当前,第一,大家通常做的就是去设计数据库,设计数据表,而后拆分了哪些字段,这就是典型的数据驱动设计。一开始是十分快,然而你会发现到前面保护的时候,你要不就是拆表,要不就是又加表加表字段,就十分的麻烦,这就是典型的数据驱动设计。界面驱动设计就是咱们通过界面上缺什么就设计什么。微服的设计准则,就是要有边界清晰的微服务,而不是小单体。边界清晰的服务也是非常容易了解,就是你这个微服务该做什么,这个服务不该做什么要晓得,而不是一味的谋求,比如说咱们的user模块,你又把订单模块放到外面了,这个服务的边界就不是十分的清晰。还有就是要有职能清晰的分层,而不是什么都放到篮子里。职能清晰的分层,后面也讲了微服务的架构层级,经典的4层架构。咱们有的时候设计零碎的时候,有时为了不便,就是把所有的货色都写在一起,比如说咱们设计一个接口层,而后设计一个应用层,而后设计一个逻辑解决层,一旦这个层级多了,就会感觉特地麻烦。后期的确比拟麻烦,然而到前期更改和保护的时候是特地不便的,咱们微服务外面同样要恪守咱们清晰的分层。接着要做本人能hold住的微服务,而不是适度拆分微服务。【为了拆而拆】怎么说?保护适度的拆分必然会带来咱们软件维护老本上的回升,因为你这个服务多了呀,你保护每个环节、每个服务之间你会有一个老本的回升,比如说咱们的集成老本、经营老本以及咱们的监控和定位问题的老本,尤其咱们排查问题,还有测试老本,微服务多了当前工夫老本会指数级的减少。企业转型中很难短时间内晋升咱们这些能力,如果咱们一些团队外面不具备这些能力,就很难hold住这些轻微的微服务。当咱们把微服务的设计好,即定义好了微服务边界当前,对服务做尽可能少的拆分过细,你把订单的保留状态也拆成一个微服务,那就过细了,所以咱们要做本人的hold住的微服务,依据你公司的目前现状,目前的人力,逐级的去拆分咱们的微服务

July 23, 2022 · 1 min · jiezi

关于go:中国上榜开发者薪酬最低国家Go-语言产品负责人离职谷歌-Carbon-旨在代替-C-思否周刊

40s 新闻速递Go 语言产品负责人到职Android 移除大部分 Fuchsia 相干代码微软切换到新的 Windows 开发周期各国开发者薪资程度统计:中国上榜寰球开发者薪酬最低国家名单英特尔发表调涨多种半导体芯片价格 最高涨幅达 20%苹果批准赔款 5000 万美元,解决 MacBook 键盘缺点诉讼案GNU arch 作者 Tom Lord 逝世Google 和甲骨文的云服务因低温下线iOS 15.6 修复显示贮存空间已满问题量子编程框架 Cirq 1.0 公布Qt Creator 8 公布Visual Studio 2022 v17.2.6 公布Rust 1.62.1 公布谷歌开源 Carbon:旨在代替 C++行业资讯Go 语言产品负责人到职Go 语言产品负责人、Hugo、Cobra、Viper 和 spf13-vim 等开源我的项目的作者 Steve Francia 发表将来到搜寻伟人加盟 Two Sigma。Steve Francia 有着煊赫的开源我的项目工作经验:领导 MongoDB 的用户体验团队,领导 Docker 的外围工程团队,当初则是 Go 语言我的项目负责人。他决定来到是感到在 Go 我的项目上的工作停滞不前,他接下来将把精力集中在数据迷信和机器学习上。 Android 移除大部分 Fuchsia 相干代码过来几年,Google 投入数以十亿美元计的资金开发名为 Fuchsia 的全新操作系统,但至今为止其成绩寥寥无几。 Fuchsia 惟一的成绩是作为 Nest 设施的底层操作系统应用,Google 曾尝试让 Fuchsia 能运行 Android 利用,为此它在 Android Open Source Project(AOSP) 创立了一个我的项目 device/google/fuchsia,设计为 Fuchsia 设施构建 Android 运行时。但本周该我的项目下的所有代码都被删除,取而代之的是一条 TODO 信息,Google 可能会用其它我的项目取代它。负责该变更的开发者来自 Fuchsia 的 Starnix 我的项目。Starnix 于 2021 年创立,旨在让 Fuchsia 能原生运行为 Linux 或 Android 构建的利用或库。 ...

July 23, 2022 · 2 min · jiezi

关于go:Go数组与切片

数组的申明形式var arr []intvar arr2 = [4]int{1,2,3,4}arr3 :=[...]int{2,3,4}数组在赋值和函数调用时的形参都是值复制当数组的长度小于4时,运行时在栈中初始化当数组的长度大于4时,启动时在动态区初始化 切片的初始化var slice1 []intvar slice2 []int=make([]int,5)var slice3 []int=make([]int,5,6)slice4:=[]int{1,2,3,4}切片的残缺复制//创立指标切片nums1 :=make([]int,len(nums),cap(nums))//将nums复制到nums1中count:=copy(nums1,nums)切片扩容后返回的地址不肯定想等能够用a=append(a,T)来保障其平安 对于go语言中的可比拟性切片,函数,map不可比拟 对于mapmap并不反对并发的读写,但反对并发的读负载因子的计算:负载因子=哈希表中的元素数量/桶数量

July 23, 2022 · 1 min · jiezi

关于go:go-读取yaml-文件

一、介绍yaml作为配置文件,根本在go中,被认为默认的配置文件格式了。yaml格局介绍,详见 https://www.ruanyifeng.com/bl...咱们看上面的yaml文件,新建redis.yaml文件 ---users: - name: "hi" age: 1 - name: "fff" age: 2redis: base: addr: "test.redis.com:6379" password: "pwd" db: "1"二、go读取yaml文件咱们应用 https://github.com/go-yaml/yaml 作为读取yaml的库。 import ( "gopkg.in/yaml.v3" "io/ioutil" "testing")func TestYaml(t *testing.T) { //1读取文件 data, err := ioutil.ReadFile("redis.yaml") if err != nil { t.Log(err) } t.Log(string(data)) //2解析文件 var y YamlFile err = yaml.Unmarshal(data, &y) t.Log(y, err)}type YamlFile struct { Users []struct { Name string Age int } Redis struct { Base struct { Addr string Password string Db string } }}

July 23, 2022 · 1 min · jiezi

关于go:Go语言单向channel的争议

背景Go内置的数据结构channel置信大家都很相熟,channel在Go语言里表演了十分重要的角色。 channel能够帮忙实现goroutine之间的通信和同步。Go语言通过goroutine和channel实现了CSP(Communicating Sequencial Process)模型。Go语言的发明人之一Robe Pike说过上面这句话: Don't communicate by sharing memory, share memory by communicating.这句话里暗藏的含意其实是心愿Go开发者应用channel来实现goroutine之间的通信。 channel分为2种类型: bi-directional channel(双向channel):既能够往channel里发送数据,也能够从channel接收数据uni-directional channel(单向channel) send-only channel:只能往channel发送数据,不能从channel接收数据,否则会编译报错receive-only channel:只能从channel接收数据,不能往channel发送数据,否则会编译报错单向channel的一个典型应用场景是作为函数或办法参数,用来管制只能往channel发送数据或者只能从channel接收数据,防止误操作。 package mainimport ( "fmt")// send-only channelfunc testSendChan(c chan<- int) { c <- 20}// receive-only channelfunc testRecvChan(c <-chan int) { result := <-c fmt.Println("result:", result)}func main() { ch := make(chan int, 3) testSendChan(ch) testRecvChan(ch)}比方下面这段程序,testSendChan的参数是一个send-only channel,testRecvChan的参数是一个receive-only channel。 实参ch是一个双向channel,Go runtime会把双向channel转换成单向channel传给对应的函数。 问题下面的例子是单向channel作为函数形参,双向channel作为函数实参,make函数创立的是一个双向channel。 那咱们能够用make来创立单向channel么?make创立的单向channel有理论应用场景么?有潜在的坑么? 咱们先看看如下2道题目: 题目1ch := make(<-chan int)close(ch)fmt.Println("ok")A: 打印okB: 运行时报错:fatal error - deadlockC: 运行时报错:painicD: 编译失败题目2c := make(chan<- int)close(c)fmt.Println("ok")A: 打印okB: 运行时报错:fatal error - deadlockC: 运行时报错:painicD: 编译失败大家能够先略微进展一下,想想这2道题的答案会是什么。 ...

July 23, 2022 · 2 min · jiezi

关于go:go-源码阅读-containerlist

一、介绍go语言提供了原生的双向链表,在源码 src/container/list/list.go双向链表中,每一个元素有prev,和next两个方向。源码中元素Element对应的 构造体为: // Element is an element of a linked list.type Element struct { //像一个,高低一个元素 next, prev *Element // The list to which this element belongs. list *List // The value stored with this element. Value interface{}}源码中List的构造体为 type List struct { root Element // sentinel list element, only &root, root.prev, and root.next are used len int // current list length excluding (this) sentinel element}通过New()函数,新建一个list。 // New returns an initialized list.func New() *List { return new(List).Init() }// Init initializes or clears list l.func (l *List) Init() *List { l.root.next = &l.root l.root.prev = &l.root l.len = 0 return l}源码中实现一个新list分为两步 ...

July 22, 2022 · 1 min · jiezi

关于go:五分钟给你的-gRPC-服务加上-HTTP-接口

gRPC 服务要加 HTTP 接口?go-zero 给大家带来极简的 RESTful 和 gRPC 服务开发体验的同时,社区又给咱们提出了新的冀望: 我想只写一次代码既要 gRPC 接口也要 HTTP 接口既要。。。也要。。。也有情理嘛!你看用户怎么说: 用户A:一套逻辑,api和rpc一起 用户B:go-zero要是能简化这一步我感觉会成为go生态中最好的微服务框架没有之一 于是,我陷入了深深的思考:用户素来是不会错的,然而咱们要不要提供呢? 于是,你看到了这篇文章。。。 咱们先提供 gRPC 服务对于这种服务,咱们太熟了。新建一个目录,就叫 grpc-restufl 吧,外面放个 sum.proto 文件 syntax = "proto3";package sum;option go_package="./pb";message Numbers { int64 a = 1; int64 b = 2;}message SumRequest { Numbers numbers =1;}message SumResponse { int64 result = 1;}service Sum { rpc Add(SumRequest) returns (SumResponse) {}}一键生成,你懂的。。。 $ goctl rpc protoc --go_out=. --go-grpc_out=. --zrpc_out=. sum.proto看看都有了啥 .├── etc│   └── sum.yaml├── go.mod├── internal│   ├── config│   │   └── config.go│   ├── logic│   │   └── addlogic.go│   ├── server│   │   └── sumserver.go│   └── svc│   └── servicecontext.go├── pb│   ├── sum.pb.go│   └── sum_grpc.pb.go├── sum│   └── sum.go├── sum.go└── sum.proto实现一下业务逻辑,将 internal/logic/addlogic.go 里的 Add 办法批改如下: ...

July 22, 2022 · 2 min · jiezi

关于go:go-struct-json-格式-tag-标签

一、介绍1.tag格局阐明struct json tag次要在struct与json数据转换的过程(Marshal/Unmarshal)中应用。 Key type `json:"name,opt1,opt2,opts..."`json的tag格局如下:一、介绍一、介绍一、介绍

July 21, 2022 · 1 min · jiezi

关于go:go-符号-引起的-作用域的坑

一、:= 符号引起的坑先看一下,上面一段代码咱们执行两个步骤第一步:p = 10第二步:p + 1预期是打印 p = 11 var p int = 5func TestYu5(t *testing.T) { //1 p=10 p, err := Ten() //2 p+1 AddP() t.Log(p, err)}func Ten() (int, error) { return 10, nil}func AddP() int { return p + 1}输入: 10为什么不是11?次要是 := 符号,在这里等同于 var此时相当于,从新申请变量,在函数内TestYu5内的p,是局部变量。作用域返回是本函数。而AddP函数里的p,用的是全局变量p 二、if,for等管制语句的作用域是{}笼罩的范畴上面的代码,咱们第一步 p = 10第二步 p = 12第三部 p = 10咱们心愿最初的输入是10 func TestYu6(t *testing.T) { //第一步 p = 10 p, err := Ten() //第二步 p = 12 p = 12 if true { //第三部,让p从新等于10 p, err := Ten() t.Log(p, err) } //最初输入p,期望值是10 t.Log(p, err)}func Ten() (int, error) { return 10, nil}输入: ...

July 21, 2022 · 1 min · jiezi

关于go:goPacket抓包性能调优

背景因为业务状况,须要抓取sip数据进行剖析,应用gopacket的pcap库进行抓包时,当有大批量数据时会呈现抓包数据不齐全的状况。 调研状况参考该文章: https://blog.csdn.net/rong_to... 发现解决该问题能够有两种计划: 1. mmap 2.pf_ring pf_ring 该计划须要装置指定的网卡驱动程序,在我这边的业务场景中不实用。mmap libcap在1.1版本时默认反对mmap, 然而在调整了各种参数,抓包还是有失落的状况,所以退而求其次,应用afpacket,该包底层应用的unix.mmap,间接应用mmap抓包。afpacket有个问题是抓127.0.0.1地址的包,抓到的数据会是双份的,抓外网ip的包OK。afPacket应用调优网卡开启混淆模式,抓包应用混淆模式调整snapshot大小最大为65535抓包超时工夫为-1.具体的代码为: 参数设置: szFrame, szBlock, numBlocks, err := afpacket.AfpacketComputeSize(1024, 65535, os.Getpagesize()) if err != nil { return err } server.handle, err = afpacket.NewAfpacketHandle("eth0", szFrame, szBlock, numBlocks, false, -1*time.Millisecond) if err != nil { return err }抓包代码: source := gopacket.ZeroCopyPacketDataSource(server.handle) dlc := gopacket.DecodingLayerContainer(gopacket.DecodingLayerMap(nil))for {select { case <-ctx.Done():return default: d, _, err := source.ZeroCopyReadPacketData() if err != nil { fmt.Println("ReadPacketData err: ", err) continue } data := make([]byte, len(d)) copy(data, d) var eth layers.Ethernet var ip4 layers.IPv4 var udp layers.UDP dlc = dlc.Put(&eth) dlc = dlc.Put(&ip4) dlc = dlc.Put(&udp) dlc = dlc.Put(layers.NewSIP()) decoder := dlc.LayersDecoder(layers.LayerTypeEthernet, gopacket.NilDecodeFeedback) decodedLayers := make([]gopacket.LayerType, 0, 10) _, err = decoder(data, &decodedLayers) if udp.NextLayerType() == gopacket.LayerTypePayload { // udp解决 }else if udp.NextLayerType() == layers.LayerTypeSIP { // sip解决 } }} 这里有几个留神点: ...

July 21, 2022 · 1 min · jiezi

关于go:golang-sync-map源码阅读

背景在开发的过程中,应用golang syncmap存储连贯信息,其中将本人封装的连贯对象指针作为key,连贯对象大略是上面的构造 type Con struct { con net.Conn addr string readBuffer []byte writeBuffer []byte ......}在跑benchmark测试的时候,发现了一个问题,就是每次跑完benchmark,无论工夫过来多久,内存始终回不到程序刚启动的水准。然而无论跑多少次benchmark,内存并不会有限升高,而是维持在方才的水准高低。过后感觉这个不是简略的内存透露。go pprof剖析内存发现是readbuffer和writeBuffer那里好多调配的内存没有开释。看到这个后果也是有点懵逼,一个会话完结的时候不仅连贯会断开,con对象也会从map中被删除,为什么还没有被开释呢。因为只有这个map的逻辑是前面加的,过后判断问题大概率出在这里,所以仔细阅读了sync map的源码。 源码源码在sync包的map.go type Map struct { mu Mutex //操作dirty时用到的锁 read atomic.Value // 只读map,只读的删除是通过更新entry中unsafe point的指向来实现,所以其实这样的删除,key占用的内存空间并没有被开释(这个场景在下文会说到) dirty map[any]*entry misses int}type readOnly struct { m map[interface{}]*entry amended bool // 如果dirty map比read map中存储的数据要全,则该字段的值为true}type entry struct { p unsafe.Pointer // *interface{}}加载key func (m *Map) Load(key any) (value any, ok bool) { read, _ := m.read.Load().(readOnly) e, ok := read.m[key] //先尝试从read map加载数据 if !ok && read.amended { //如果没有找到数据,并且read map和dirty有差别 m.mu.Lock() read, _ = m.read.Load().(readOnly) e, ok = read.m[key] if !ok && read.amended { //这里是进行一个double check e, ok = m.dirty[key] //减少一下miss的次数,miss次数达到dirty长度就会用dirty笼罩readmap m.missLocked() } m.mu.Unlock() } if !ok { return nil, false } return e.load()}func (m *Map) missLocked() { m.misses++ if m.misses < len(m.dirty) { return //当miss的次数大于等于dirty的长度的时候,就用dirty笼罩readmap m.read.Store(readOnly{m: m.dirty}) m.dirty = nil m.misses = 0}func (e *entry) load() (value any, ok bool) { p := atomic.LoadPointer(&e.p) //不为空并且不是擦除状态,这个擦除状态是指的是,当从read map向dirty同步数据的时候,如果这个key对应value的entry指向的是nil(删除状态),就不同步到dirty,而是标记为擦除(expunged)状态思考 为什么要设置为擦除状态当发现read map中的一个key是擦除状态的时候,能够阐明dirty非空,并且dirty外面没有这个key。这样在store的时候就能够通过判断擦除状态来保障,dirty外面没有的key,会被sotre到dirty。 if p == nil || p == expunged { return nil, false } return *(*any)(p), true}存储key ...

July 20, 2022 · 3 min · jiezi

关于go:golang从入门到精通一变量定义

变量定义 var x String = “abc”;x := 123 暗藏类型,主动判断类型//批量定义var ( a string = "1" b int = 1)const ( a = 1 b = "abc")const ( s = iota //iota计数器 常量计数器,会重置为0,从新计数, 每隔一行加1,如果有其余定义占行,会再累加 i k)fmt.Println(s) //0fmt.Println(i) //1fmt.Println(k) //2常量定义 const 不须要指定类型 const abc = 123自定义类型 //定义方法类型type f func() //定义接口类型type i interface { }//定义构造体type people struct { Name string age int}t := people{ name:"ss" age:10}函数、办法定义 //办法定义, 依据构造体定义func (u people) getName() string { return u.name}//先创立构造体,能力应用办法,可设想成 newt := people{ //调用时,t会传递给u name:"ss" age:10}t.getName() // 应用接口,须要借助构造体,先定义个类型,是接口类型,而后构造体实现了接口的办法,这个构造体就相当于接口的继承,而后应用构造体调用办法type Retriever interface { Get(string) string}var r Retriever // Retriever接口r = re.Retriever{"abc"} //Retriever构造体实现了Retriever接口 能够当做Retriever接口传入fmt.Println(r.Get("abc"))案例 ...

July 20, 2022 · 1 min · jiezi

关于go:lets-go2022年读书活动招募书第1期

作为一名编程人员,时常有一个想法,怎么精通某种技术?而后,业内大牛给你分享了一条学习路线,当你看完这条路线之后,之前低落的情绪霎时高涨下来,因为“万丈高楼平地起”,那条路的止境兴许很美妙——成为业内大牛,然而,无论如何这条路还得你本人去走,并且这条路很长,也并不好走。 尽管这条路早已注定是艰巨的,然而,如果这条路上能有同行者,对咱们来说也是一种宽慰。这就是这个读书流动的初衷,寻找一些气味相投的人,同时将本人在编程之路上的教训帮忙到一些有须要的人。 本次读书流动的主题是“let’s go”,之所以应用这个主题,起因有二:一是因为此次读书所用的教材为《The Go Programming Language》,即“go”;二是此次读书流动为第1期读书流动,让咱们开始吧。 浏览《The Go Programming Language》,旨在以下方面晋升和拓展的咱们能力:1、Go语言根本用法是怎么样的,和其它语言的区别是什么?。2、如何浏览英文技术书籍? 一、教材1.《The Go Programming Language》作者:Alan A. A. Donovan / Brian W. Kernighan出版社:机械工业出版社https://book.douban.com/subject/26859123/ 二、流动模式本期读书流动从2022年8月1日起,预计继续3个月左右,流动完结后不再招收人员入群。每天早上6:00开始,锁定1小时认真读书。咱们会在每天6点前公布当日读书与答题工作,成员须要每天24:00前实现工作,如果间断3天无奈无奈实现工作,那么清退出群(注:清退出群不退款,请思考分明之后再口头)。 三、退出形式费用:19.9元。 四、付款形式请扫以下任意一个二维码,领取实现后,将订单号和QQ号发送给微信号codists,在24小时之内邀请进群。咱们会在QQ群提交作业,请自行购买图书。留神:付款后不再退款,请思考分明后再口头。 1.微信领取 2.支付宝领取 五、问答1.入群后可不可以本人看,不实现工作?答:不能够。如果间断3天不实现工作,清退出群,且不退款,请思考分明后再口头。2.做不到每天都读书怎么办?答:很多事件都有一个过程,你只有做了才晓得你可不可以做到。3.应用纸质书还是电子书?答:无论电子书还是纸质书都能够,请自行购买,同时不要在群里流传电子书,否则清退出群。

July 20, 2022 · 1 min · jiezi

关于go:go-for循环中的作用域

一、介绍var a int a := 0 二、for循环go协程作用域1.咱们先看下最简略的for如下 package mainimport "fmt"func main() { for i := 0; i < 2; i++ { go func() { fmt.Println(i) }() }}下面的代码,最初没有输入。咱们的冀望输入 0 1 的欲望落空了,什么起因?程序执行工夫图如上图,咱们发现在下面的程序有2种状况1.当主过程完结,goroutine2,goroutine3 都还没执行完,则没有输入。2.状况2,如下图 goroutine2 执行完,输入了1 !!!!留神不是0!!!!从下面学到的解决竞态4中计划,咱们用waitGroup阻塞主过程,改良代码如下: package mainimport ( "fmt" "sync")func main() { wg := sync.WaitGroup{} for i := 0; i < 2; i++ { wg.Add(1) go func() { fmt.Println(i) wg.Done() }() } wg.Wait()}输入如下: 22终于两个goroutine都执行,但后果和咱们其余的0,1 齐全不一样。为啥?当goroutine2,goroutine3 打印的时候,main goroutine 曾经将 i变成2了,而在整个for内,i是同一个变量。此时就打印变成了2了。2.for循环中go协程作用域咱们看上面的示例代码 package mainimport ( "fmt" "time")func main() { // for 循环作用域开始 for i := 0; i < 2; i++ { go func() { fmt.Println(i) }() }//for 循环作用域完结 time.Sleep(time.Second)}输入后果如下: ...

July 20, 2022 · 2 min · jiezi

关于go:go-channel-详细介绍

一、介绍channel是用于goroutine的数据通信

July 20, 2022 · 1 min · jiezi

关于go:go源码阅读-context

一、介绍咱们在命令行 输出 go doc context 能够看到多 context包的介绍。context高低问,是连贯不同的goroutine,让每个协程能够有父子关系,并且领有本人的独特的值WithValue(),或者解决超时WithTimeout(),定时WithDeadline(),勾销协程WithCancel()操作。在go官网博客https://go.dev/blog/context也有想起的介绍。 源码地址 src/context/context.go在context包里,共有4种类型的上下文 上下文如何获取作用emptyCtxBackground()或TODO()初始化父级上下文valueCtxWithValue()初始化一个带key,value的子级上下文cancelCtxWithCancel()初始化一个能够勾销的子级上下文timerCtxWithDeadline()或WithTimeout()初始化一个带有定时以及能够勾销的子级上下文从协程的角度来看如下图: 从上下文的角度来看如下图: 二、emptyCtx 初始化默认父级上下文源码如下: var ( background = new(emptyCtx) todo = new(emptyCtx))func Background() Context { return background}func TODO() Context { return todo}type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{}}type emptyCtx intfunc (*emptyCtx) Deadline() (deadline time.Time, ok bool) { return}func (*emptyCtx) Done() <-chan struct{} { return nil}func (*emptyCtx) Err() error { return nil}func (*emptyCtx) Value(key interface{}) interface{} { return nil}func (e *emptyCtx) String() string { switch e { case background: return "context.Background" case todo: return "context.TODO" } return "unknown empty Context"}emptyCtx 是是一个实现了Context接口的 上下文。没有做什么逻辑,只是为了实现一个变量,可能让Background()和 TODO()调用。 ...

July 20, 2022 · 1 min · jiezi

关于go:脉脉网友出的一道简单-Go-面试题你能答对吗

大家好,我是煎鱼。 前段时间脉脉在搞一个 “我来出一道面试题” 的探讨系列,其中一位脉友 @在宿雾参观的小冬瓜 出了一道 Go 题目。 来和煎鱼一起答复本人答的准不准,常识把握的怎么样吧。 (大家都说很简略,后果在投票上 50 50,错的人更多...) 题目Go 题目如下: func main() { var nums1 []interface{} nums2 := []int{1, 3, 4} num3 := append(nums1, nums2) fmt.Println(len(num3))}请抉择程序的运行后果(答案)是什么? A:1;B:3;C:4;D:编译失败。答案题主仿佛是西昌学院的小伙伴。这里配上原题目的图(挡一下答案,选择题选完再往下看)。 如下图: 程序运行后果: 1也就是答案是 A,输入后果是 1。 你答对了吗?咱们持续。 既然变量 num3 的长度是 1。那这里 1 个里,塞的是什么。 代码如下: var nums1 []interface{} nums2 := []int{1, 3, 4} num3 := append(nums1, nums2) fmt.Println(num3)输入后果是 1,还是 3,还是 4? 程序运行后果: [[1 3 4]]这一次你答对了吗? 是为什么呢? 解析这个 Go 题目,实质上是比拟容易被误导,一个不小心就选错了。咱们来看看 append 函数的官网定义是怎么样的。 ...

July 19, 2022 · 1 min · jiezi

关于go:支持SagaTccXa混用支持gRPCHTTP混用的分布式事务模式

Workflow 模式是github.com/dtm-labs/dtm独创推出的模式,在这个模式下,能够混合应用XA、SAGA、TCC,也能够混合应用HTTP、gRPC,用户能够对分布式事务外面的绝大部分内容进行定制,具备极大的灵活性,上面咱们以转账场景,讲述如何在Workflow下进行实现。 workflow例子Workflow模式下,既能够应用HTTP协定,也能够应用gRPC协定,上面以gRPC协定作为例子,一共分为一下几步: 初始化 SDK注册workflow执行workflow首先须要在应用workflow前对 SDK 的 Workflow 进行初始化:import "github.com/dtm-labs/dtmgrpc/workflow"// 初始化workflow SDK,三个参数别离为:// 第一个参数,dtm服务器地址// 第二个参数,业务服务器地址// 第三个参数,grpcServer// workflow的须要从"业务服务器地址"+"grpcServer"上接管dtm服务器的回调workflow.InitGrpc(dtmGrpcServer, busi.BusiGrpc, gsvr)而后须要注册workflow的处理函数wfName := "wf_saga"err := workflow.Register(wfName, func(wf *workflow.Workflow, data []byte) error { req := MustUnmarshalReqGrpc(data) wf.NewBranch().OnRollback(func(bb *dtmcli.BranchBarrier) error { _, err := busi.BusiCli.TransOutRevert(wf.Context, req) return err }) _, err := busi.BusiCli.TransOut(wf.Context, req) if err != nil { return err } wf.NewBranch().OnRollback(func(bb *dtmcli.BranchBarrier) error { _, err := busi.BusiCli.TransInRevert(wf.Context, req) return err }) _, err = busi.BusiCli.TransIn(wf.Context, req) return err})这个注册操作须要在业务服务启动之后执行,因为当过程crash,dtm会回调业务服务器,持续未实现的工作上述代码NewBranch会创立一个事务分支,一个分支会包含一个正向操作,以及全局事务提交/回滚时的回调OnRollback/OnCommit会给以后事务分支指定全局事务回滚/提交时的回调,上述代码中,只指定了OnRollback,属于Saga模式这外面的 busi.BusiCli 须要增加workflow的拦截器,该拦截器会主动把rpc的申请后果记录到dtm,如下所示 ...

July 19, 2022 · 1 min · jiezi

关于go:极客时间Go进阶训练营全新升级第4期百度网盘完结

> Download: https://www.itwangzi.cn/3389....============================================================ Golang 和不便的 goroutine 一个 goroutine 是特指的是被 Golang runtime 所治理的用户态线程,用户态线程也称协程。在 Golang 中应用 goroutine 是极其不便的,goroutine 也是 Go 语言最吸引人的中央之一。通过 Go 关键字就可能在 runtime 里创立一个新的 Go 协程 (goroutine)。学会创立一个 goroutine:https://go.dev/tour/concurren... go say("world") goroutine 因为其比照操作系统线程非常明显的特点: 上下文切换开销更少 堆栈空间占用通常更少 goroutine 之间的通信模型更不便。 goroutine 调度对写代码的人来说是通明的。 在 Golang 程序中大量存在,能够说,不必它就相当不必 Golang。 也因为这种便宜好用的 Go协程,使得大量应用 Golang 编写的利用大行其道,明天咱们来讲讲当应用 Golang 的这个个性开发利用时与 Linux namespace 相干的一些副作用。 GPM 模型 Golang runtime 从开始到演化成现在的 G-P-M 模型定义中,一个特定 G 代表一个特定 goroutine,M 代表操作系统线程 OSthread,P 则代表 Runtime 中的逻辑处理器。 G 是 Go 中的根本调度单位,是 Go 语言层面实现并发的最小粒度。G 的生命周期由 Go runtime 跟踪。goroutines 切换只需保留三个寄存器:Program Counter, Stack Pointer and BP。G 的 goid 被设置成公有。 ...

July 18, 2022 · 4 min · jiezi

关于go:Go语言WEB框架请求结果处理

申请后果解决wego框架反对以字符串、json、xml、html等格局响应HTTP申请,相应的函数定义如下: Write(code int, contentType string, data []byte)WriteText(code int, data string)WriteJSON(code int, obj interface{})WriteXML(code int, obj interface{})WriteHTML(code int, filename string, data interface{})输入JSON数据wego对于JSON的反对十分好,能够十分不便的开发一个基于JSON输入的API。若要返回JSON格局的申请后果,能够应用WriteJSON()函数: func writeJson(c *wego.WebContext) { var user User user.ID = 1 user.Name = "demo" user.Age = 12 c.WriteJSON(200, user)}/*输入后果为:{"Name":"demo","ID":1,"Age":12}*/应用WriteJSON函数输入的JSON字符串是扁平的,没有进行缩进显示。若须要输入更加好看的json数据,则能够应用WriteIndentedJSON()函数: func writeIndentedJSON(c *wego.WebContext) { var user User user.ID = 1 user.Name = "demo" user.Age = 12 c.WriteIndentedJSON(200, user)}/*输入后果为:{ "Name": "demo", "ID": 1, "Age": 12}*/输入JSONP数据JSONP能够跨域,次要是利用了script标签跨域的能力,script标签能够援用任何域名下的JS文件。wego反对输入JSONP申请后果。示例代码如下: html代码: <html lang="en"><head> <meta charset="utf-8"> <title>file upload</title> <script type="text/javascript" src="http://127.0.0.1:8080/jsonp?callback=alert"></script></head><body></body></html>服务端代码: ...

July 18, 2022 · 3 min · jiezi

关于go:Go语言WEB框架请求参数处理

获取申请参数wego框架中申请参数能够应用一个对立的Param对象来获取,Param对象可获取以下类型的参数: URL门路参数<< 门路参数是从url的Path中匹配的参数,门路参数通常在冒号路由或星号路由中定义,并在url申请的Path中匹配而获取的。URL查问参数<< URL查问参数,是URL申请中以?为终点的形如k1=v1&k2=v2...这样的字符串解析所得的参数。Form参数<< Form参数又称作表单参数,这里的表单数据指的是浏览器将表单数据通过POST申请提交给服务器由服务器解析出的数据。< 浏览器将发送POST申请时的Content-Type通常为x-www-form-urlencoded或者是multipart/form-data。在wego中通过c.Param.GetXXX函数来获取申请参数: func TestGetParam(t *testing.T) { web, _ := NewWeb() web.GET("/user", func(c *WebContext) { name := c.Param.GetString("name") if name.Error != nil { t.Error(name.Error) } age := c.Param.GetInt("age") if age.Error != nil { t.Error(age.Error) } c.WriteText(200, name.Value) }) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/user?name=lisi&age=12", nil) web.ServeHTTP(w, req)}为了不便获取各种类型的参数,wego提供了一些列GetXXX函数用于参数的获取: GetString(key string, defaultValue ...string) ValidStringGetBool(key string, defaultValue ...bool) ValidBoolGetInt(key string, defaultValue ...int) ValidIntGetInt32(key string, defaultValue ...int32) ValidInt32GetInt64(key string, defaultValue ...int64) ValidInt64GetFloat(key string, defaultValue ...float64) ValidFloatGetTime(key string, format string, defaultValue ...time.Time) ValidTimeGetXXX函数没有间接返回XXX类型的值,例如GetInt返回的不是int类型的值,而是一个ValidInt的类型的值: ...

July 18, 2022 · 3 min · jiezi

关于go:引入-CloudWeGo-后飞书管理后台平台化改造的演进史

随着企业用户逐步增多,面对不同场景下不同需要和技术问题,CloudWeGo 团队将会继续分享不同企业的落地实际,蕴含不同行业面临的技术问题、选型参考和最终落地性能和应用分享,来帮忙更多用户开始应用 CloudWeGo。 飞书治理后盾是飞书套件专为企业管理员提供的信息管理平台,在单体利用架构下,它面临了一系列的挑战。它通过引入 Kitex 泛化调用对飞书治理后盾进行平台化革新,使之变为业务网关,提供一套对立的规范和通用服务,让有管控诉求的套件业务方能疾速实现能力集成,并且提供统一的体验。最终实现了飞书治理后盾作为企业对立数字化治理平台的愿景。 本文将从三个方面为大家解说 Kitex 泛化调用在飞书治理后盾平台化革新过程中的落地实际: 架构和挑战,即飞书治理后盾单体架构面临的各种挑战;平台化构想,即飞书治理后盾平台化构想和架构降级;平台化实现,包含微前端技术架构、泛化调用实际和性能扩大。以下内容来自飞书业务中台后端架构师汪浩在 CloudWeGo 携手稀土掘金独特举办、以《CloudWeGo:从开源、凋谢到企业落地》为主题的 Meetup 流动中的分享。 01 架构和挑战飞书是真正的一站式企业沟通与合作平台,整合视频会议、即时消息、日历、云文档、邮箱、工作台等性能于一体,立志打造高效的办公形式,减速企业成长。飞书治理后盾(以下简称 Admin)是飞书套件专为企业管理员提供的信息管理平台,企业管理员可通过后盾治理企业设置、组织架构、工作台和会议室等性能。下图是飞书治理后盾的界面。 平台革新背景飞书采纳的是 all-in-one 的套件模式,Admin 作为整个套件对立的治理后盾,承接了包含组织治理、云文档、视频会议、邮箱、开放平台等 10 多个业务线的管控需要。始终以来的开发模式是各业务方间接在 Admin 的代码仓库提交代码或者由 Admin 团队负责 Web 层逻辑的开发。 下图是目前飞书治理后盾中包含的一些性能。之前的开发模式是业务方间接在 Admin 的代码仓库中提交代码,或者由业务方给 Admin 团队提供一些需要,由飞书来负责 Web 层逻辑的开发。 从飞书初创开始,Admin 就是以单体利用的模式开发的,随着后续飞书整体的演进,团队越来越多,不同业务线的团队也会有一些管控需要要接入 Admin 平台,因而他们就间接在代码仓库中提交代码。 Admin 架构下图是 Admin 旧架构图。下面是 Admin 前端,它其实就是 Node 层的单体,两头是 Admin 后端,它基于外部单体 HTTP 的 Web 服务,会通过 RPC 调用到其余业务线的微服务。 面临的问题而在这个架构下会面临一些问题。第一个问题是业务迭代慢,因为所有业务线都只能在 Admin 的代码仓库里进行开发和发版,因而这些业务线齐全依赖 Admin 的研发资源和迭代流程,Admin 的研发资源被过多的耗在各业务的迭代中,无奈疾速反对本身的业务布局,如组织架构、平安、KA 等因为飞书是 To B 的产品,因而发版节奏不会很快。如果各个业务线有一些比拟紧急的需要,也只能跟 Admin 的节奏,这就会造成发版节奏不统一,研发资源不匹配,导致 Admin 会成为业务迭代的瓶颈。 ...

July 18, 2022 · 2 min · jiezi

关于go:go源码阅读-containerring

一、介绍ring是一个首尾相连的list,源码位于 src/container/ring/ring.go 其中每一个元素的定义如下: // A Ring is an element of a circular list, or ring.// Rings do not have a beginning or end; a pointer to any ring element// serves as reference to the entire ring. Empty rings are represented// as nil Ring pointers. The zero value for a Ring is a one-element// ring with a nil Value.//type Ring struct { next, prev *Ring Value interface{} // for use by client; untouched by this library}通过New办法能够创立一个特定大小的ring,例如: ...

July 18, 2022 · 1 min · jiezi

关于go:Go语言ORM框架快捷查询函数的使用

快捷查问函数大多数状况下您都是在应用worm支提供的Model形式(持构造体字段映射)来拜访数据库,但有些时候应用Model形式显然有些轻便。例如您可能只须要查问一个记录的一个字段的值,这种状况下若应用Model形式则比拟繁琐。worm提供了一些快捷查问函数来应答这种需要,例如DbTable的GetString()函数,该函数克用于查问一个记录的一个字符串类型的字段。这些快捷查问函数能够用于原生SQL以及SQLBuilder模式,这些快捷函数的用法以上两种模式下的用法基本上是统一的,本文中应用SQLBuilder模式来阐明这些快捷函数的应用办法。 main函数package mainimport ( "database/sql" _ "github.com/go-sql-driver/mysql" log "github.com/haming123/wego/dlog" "github.com/haming123/wego/worm")func mysql_open(cnnstr string) (*sql.DB, error) { db, err := sql.Open("mysql", cnnstr) if err != nil { return nil, err } err = db.Ping() if err != nil { return nil, err } return db, nil}func main() { //创立数据连接池 cnnstr := "user:passwd@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True" db_cnn, err := mysql_open(cnnstr) if err != nil { log.Error(err) return } //初始化ORM worm.InitMysql(db_cnn) //显示SQL语句log worm.ShowSqlLog(true)}阐明: worm代码的下载go get github.com/haming123/wegoworm.ShowSqlLogworm.ShowSqlLog用于管制sql日志的显示,倡议测试环境下关上sql日志的显示的开关,这样能够看到每个数据库操作的sql语句以及执行工夫,不便疾速定位问题。数据库的反对目前worm反对的数据库有:mysql、postgres、sqlite、sqlserver, 本文的例子中采纳了mysql数据库。数据库表//建表语句CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(30) DEFAULT NULL, `age` int(11) DEFAULT NULL, `passwd` varchar(32) DEFAULT NULL, `created` datetime DEFAULT NULL, PRIMARY KEY (`id`));查问某个记录是否存在有些状况下您不须要获取一个记录的数据,而是只须要查询数据库中是否存在某个记录,这种状况下能够应用Exist()函数: ...

July 18, 2022 · 2 min · jiezi

关于go:GO实践笔记

背景已用GO进行我的项目实际。浏览其它开源我的项目,发现自己代码实现不够标准。规范库不够相熟。error包谬误的包裹,应用 Unwrap() error。谬误的比拟,应用 Is(err, target error) bool。谬误的类型判断,应用 As(err error, target interface{}) bool。以上做法的益处是能兼容寄存和判断整个err链路的全副err,而不仅是以后的err。context包当处于申请顶层的时候,应用 Background() Context 获取一个空的context实例。当不晓得传递哪一个context的时候,可应用 TODO() Context 获取一个空实例长期应用。valueCtx只实现了创立和获取值的办法,其它接口所需办法为父context的代理办法。cancelCtx实现了 Done() <-chan struct{} 办法,这个构造采纳懒加载,在context调用勾销办法后,该chan被敞开。实现的 Value(key interface{}) interface{} 办法用于获取cancelCtx本身。Err() error 办法用于返回err。timerCtx实现了Deadline() (deadline time.Time, ok bool),利用定时器及cancelCtx实现超时勾销的能力。WithDeadline和WithTimeout都实现自timerCtx。包裹valueCtx时,应应用自定义的非导出类型和非导出变量作为key,并提供封装好的获取值的办法,防止在内部应用key间接获取值。这样能够躲避全局key的净化问题。

July 18, 2022 · 1 min · jiezi

关于go:Golang-RPC-一Go标准库的简单实现-介绍使用

如果咱们想在服务端为客户端提供一个打印一个输出字段的服务,借助net/rpc,咱们能够这样实现: 服务端package mainimport ( "log" "net" "net/rpc")//结构一个类 名字是HelloServicetype HelloService struct{}//给这个类绑定一个Hello办法 实现打印的性能,这个办法只能有两个可序列化的参数,其中第二个参数是指针类型,并且返回一个error类型,同时必须是公开的办法func (item *HelloService) Hello(req string, reply *string) error { *reply = "server-hello " + req return nil}func main() { //将HelloService的对象注册为一个RPC服务 rpc.RegisterName("HelloService", new(HelloService)) listener, err := net.Listen("tcp", ":1234") if err != nil { log.Fatal("ListenTCP error:", err) } //建设一个惟一的TCP链接,并且通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。 conn, err := listener.Accept() if err != nil { log.Fatal("Accept error:", err) } rpc.ServeConn(conn)}客户端package mainimport ( "fmt" "log" "net/rpc")func main() { //通过rpc.Dial拨号RPC服务 client, err := rpc.Dial("tcp", "localhost:1234") if err != nil { log.Fatal("dialing", err) } var reply string //通过client.Call调用具体的RPC办法 //在调用client.Call时,第一个参数是用点号链接的RPC服务名字和办法名字, //第二和第三个参数别离咱们定义RPC办法的两个参数。 err = client.Call("HelloService.Hello", " client-Hello", &reply) if err != nil { log.Fatal(err) } fmt.Println(reply)}运行后果: ...

July 18, 2022 · 1 min · jiezi

关于go:Go语言ORM包使用worm构造查询条件

结构查问条件worm是一款不便易用的Go语言ORM库。worm支Model形式(持构造体字段映射)、原生SQL以及SQLBuilder三种模式来操作数据库,并且Model形式、原生SQL以及SQLBuilder可混合应用。Model形式、SQL builder反对链式API,可应用Where, And, Or, ID, In, Limit, GroupBy, OrderBy, Having等函数结构查问条件。也能够可通过Join、LeftJoin、RightJoin来进行数据库表之间的关联查问。本文通过一些例子来阐明如何应用worm来结构查问条件。 main函数package mainimport ( "database/sql" _ "github.com/go-sql-driver/mysql" log "github.com/haming123/wego/dlog" "github.com/haming123/wego/worm")func mysql_open(cnnstr string) (*sql.DB, error) { db, err := sql.Open("mysql", cnnstr) if err != nil { return nil, err } err = db.Ping() if err != nil { return nil, err } return db, nil}func main() { //创立数据连接池 cnnstr := "user:passwd@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True" db_cnn, err := mysql_open(cnnstr) if err != nil { log.Error(err) return } //初始化ORM worm.InitMysql(db_cnn) //显示SQL语句log worm.ShowSqlLog(true)}阐明: ...

July 18, 2022 · 3 min · jiezi

关于go:Golang-非主流-打包静态资源方案

说到往 Go 程序外面打包进其余非 *.go 资源,在 Go1.16 之前有 go-bindata 第三方开源反对。 在 Go1.16 引入了新个性 embed,不依赖第三方就能嵌入动态资源权限。 然而在我的项目中,以上两种计划我都没用,转而自研了一套计划。 不想听我bb心路历程的,间接跳到 开整 环节看最终实现。背景在2021年初,我在参加的我的项目 go-mod-graph-chart 时,须要把前端资源集成到一个由Go语言构建的 命令行 程序中。 都说到这了,就介绍下 go-mod-graph-chart ,它是一个 将 go mod graph 命令输入的文本可视化 命令行 工具(相似于graphviz),在我的项目目录下执行go mod graph 会输入以后我的项目,所依赖的第三方包,以及第三方包又依赖了什么包。但当你理论应用时,你会看到一堆的文本, 命令输入后果如下: $ go mod graphgo-learn github.com/antlabs/pcurl@v0.0.7go-learn github.com/bxcodec/faker/v3@v3.6.0go-learn github.com/go-sql-driver/mysql@v1.5.0go-learn github.com/jinzhu/copier@v0.3.5go-learn github.com/pingcap/parser@v0.0.0-20220118030345-6a854bcbd929go-learn github.com/smartystreets/goconvey@v1.7.2go-learn golang.org/x/text@v0.3.7go-learn moul.io/http2curl@v1.0.0github.com/antlabs/pcurl@v0.0.7 github.com/gin-contrib/gzip@v0.0.1github.com/antlabs/pcurl@v0.0.7 github.com/gin-gonic/gin@v1.6.3github.com/antlabs/pcurl@v0.0.7 github.com/guonaihong/clop@v0.0.9github.com/antlabs/pcurl@v0.0.7 github.com/guonaihong/gout@v0.0.12github.com/antlabs/pcurl@v0.0.7 github.com/stretchr/testify@v1.6.1github.com/pingcap/parser@v0.0.0-20220118030345-6a854bcbd929 github.com/cznic/golex@v0.0.0-20181122101858-9c343928389cgithub.com/pingcap/parser@v0.0.0-20220118030345-6a854bcbd929 github.com/cznic/mathutil@v0.0.0-20181122101859-297441e03548...而应用 gmchart 这个工具,将其可视化为多级树状构造。 如下图: 在散发这个命令行工具,如果还要带着动态资源,或是让用户先下个 graphviz ,体验就很不好了。 于是我就想有什么方法,将动态资源打包到 *.go 代码里。 很不巧在2020年底时, Go1.16 embed 还未推出 ,但我要解决这个问题。go-bindata 在过后无疑是最受欢迎的计划,但会引入第三方依赖。这个时候,我代码洁癖上来了,之前我用gin做了http服务,起初发现我的项目只引入了 gin,我把gin换成内置的 http 服务 后,就变成无依赖的我的项目了。所以,我想持续放弃 no dependency 。我感觉这个性能应该不难,本人也能写啊。 ...

July 17, 2022 · 2 min · jiezi

关于go:Golang-接口与多态

假如我有一个HUAWEI类,要实现Phone接口,能够这样做: package mainimport "fmt"//定义一个接口type Phone interface { call()}//定义一个类type HUAWEI struct { name string}//用下面的HUAWEI类实现下面的Phone接口func (myPhone HUAWEI) call() { fmt.Println("this is the coolest phone all around the world")}func main() { thisPhone := new(HUAWEI) thisPhone.call()}

July 17, 2022 · 1 min · jiezi

关于go:迈向高级的Java面试突围课完结

> Download: 迈向高级的Java面试解围课=============================================================== 1、java 容器都有哪些? 罕用容器的图录:] 2. Collection 和 Collections 有什么区别?java.util.Collection 是一个汇合接口(汇合类的一个顶级接口)。它提供了对汇合对象进行基本操作的通用接口办法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的汇合提供了最大化的对立操作形式,其间接继承接口有List与Set。 Collections则是汇合类的一个工具类/帮忙类,其中提供了一系列静态方法,用于对汇合中元素进行排序、搜寻以及线程平安等各种操作。 List、Set、Map 之间的区别是什么? HashMap 和 Hashtable 有什么区别?hashMap去掉了HashTable 的contains办法,然而加上了containsValue()和containsKey()办法。 hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。 hashMap容许空键值,而hashTable不容许。 如何决定应用 HashMap 还是 TreeMap?对于在Map中插入、删除和定位元素这类操作,HashMap是最好的抉择。然而,如果你须要对一个有序的key汇合进行遍历,TreeMap是更好的抉择。基于你的collection的大小,兴许向HashMap中增加元素会更快,将map换为TreeMap进行有序key的遍历。 说一下 HashMap 的实现原理?HashMap概述:HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并容许应用null值和null键。此类不保障映射的程序,特地是它不保障该程序恒久不变。 HashMap的数据结构:在java编程语言中,最根本的构造就是两种,一个是数组,另外一个是模仿指针(援用),所有的数据结构都能够用这两个根本构造来结构的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。 当咱们往Hashmap中put元素时,首先依据key的hashcode从新计算hash值,杜绝hash值得到这个元素在数组中的地位(下标),如果该数组在该地位上曾经寄存了其余元素,那么在这个地位上的元素将以链表的模式寄存,新退出的放在链头,最先退出的放入链尾.如果数组中该地位没有元素,就间接将该元素放到数组的该地位上。 须要留神Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来进步查问效率,从原来的O(n)到O(logn) 说一下 HashSet 的实现原理?HashSet底层由HashMap实现 HashSet的值寄存于HashMap的key上 HashMap的value对立为PRESENT ArrayList 和 LinkedList 的区别是什么?最显著的区别是 ArrrayList底层的数据结构是数组,反对随机拜访,而 LinkedList 的底层数据结构是双向循环链表,不反对随机拜访。应用下标拜访一个元素,ArrayList 的工夫复杂度是 O(1),而 LinkedList 是 O(n)。 如何实现数组和 List 之间的转换?List转换成为数组:调用ArrayList的toArray办法。 数组转换成为List:调用Arrays的asList办法。 ArrayList 和 Vector 的区别是什么?Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行扭转,你应该应用CopyOnWriteArrayList。 ArrayList比Vector快,它因为有同步,不会过载。 ArrayList更加通用,因为咱们能够应用Collections工具类轻易地获取同步列表和只读列表。 Array 和 ArrayList 有何区别?Array能够包容根本类型和对象,而ArrayList只能包容对象。 Array是指定大小的,而ArrayList大小是固定的。 Array没有提供ArrayList那么多功能,比方addAll、removeAll和iterator等。 在 Queue 中 poll()和 remove()有什么区别?poll() 和 remove() 都是从队列中取出一个元素,然而 poll() 在获取元素失败的时候会返回空,然而 remove() 失败的时候会抛出异样。 ...

July 16, 2022 · 1 min · jiezi

关于go:Golang-实现继承

Golang的继承能够通过构造体外面蕴含匿名构造体实现,具体,比方iPhone这个构造体要继承法phone这个构造体能够这样写: package mainimport "fmt"type phone struct { design_place string production_place string}type iphone struct { brand string phone}func main() { thePhone := phone{ design_place: "California", production_place: "China", } thisPhone := iphone{ brand: "Apple", phone: thePhone, } fmt.Println(thisPhone.production_place, thisPhone.brand)}

July 16, 2022 · 1 min · jiezi

关于go:Golang-给结构体绑定方法

如果咱们有一个个人档案的构造体,而后想给这个构造体绑定办法能够这样: package mainimport "fmt"//定义一个装档案的构造体type Archive struct { name, gender string age int mom *Archive dad *Archive}//定义一个和档案构造体绑定的办法func (person Archive) FormatArchive() { fmt.Printf("name: %s\n", person.name) fmt.Printf("gender: %s\n", person.gender) fmt.Printf("age: %d\n", person.age)}func main() { // 实例化一个构造体 bill := Archive{name: "bill", age: 17, gender: "Male"} // 调用构造体绑定的办法 bill.FormatArchive()}那么,当咱们想在构造体绑定的办法上扭转构造体的数据的时候,咱们须要用指针,具体就是这样: package mainimport "fmt"//定义一个装档案的构造体type Archive struct { name, gender string age int mom *Archive dad *Archive}//定义一个和档案构造体绑定的办法func (person Archive) FormatArchive() { fmt.Printf("name: %s\n", person.name) fmt.Printf("gender: %s\n", person.gender) fmt.Printf("age: %d\n", person.age)}//定义一个扭转实力参数的函数func (person *Archive) decrease_age() { person.age -= 1}func main() { // 实例化一个构造体 bill := Archive{name: "bill", age: 17, gender: "Male"} // 调用构造体绑定的办法 bill.FormatArchive() bill.decrease_age() bill.FormatArchive()}

July 16, 2022 · 1 min · jiezi

关于go:Golang-单向chanel的定义和使用

如果咱们须要一个信道专门发送数据,一个信道专门接收数据,能够这样写:(咱们假如要发送和接管的数据是9): package mainimport ( "fmt" "time")//只写信道定义type Writter = chan<- int//只读信道定义type Reader = <-chan intfunc main() { //申明一个信道 var ch = make(chan int) go func() { var writter Writter = ch fmt.Println("写入数据:9") writter <- 9 }() go func() { var reader Reader = ch data := <-reader fmt.Printf("读出数据:%d", data) }() time.Sleep(time.Second)}

July 16, 2022 · 1 min · jiezi

关于go:2022最新慕课网实战课程大全资料完整百度网盘分享

课程阐明所有课程百分百高清,残缺,原画,蕴含所有的 视频+素材+课件+源码,官网同步体验!所有课程格局 MP4格局无密 能够通过网盘在线学习也可下载到本地,方便快捷!目前已收录二十多家IT机构累计3000+课程,且在继续更新中... 课程下载 IT课程获取 : 慕课网全套课程 点击进入资源下载页 :  资源下载 目录一览从0开始 独立实现企业级Java电商网站开发【完结无密】go语言教程零根底入门到精通——2019版玩转算法与数据结构所向无敌的响应式开发扛得住的MySQL数据库架构Web App用组件形式开发全站Android自动化测试实战 Java篇支流工具,框架,脚本高性能可扩大 MySQL数据库架构设计与优化组件化封装思维实战Android App玩转算法面试 从真题到思维全面晋升算法思维Thinkphp5.0仿百度糯米开发多商家电商平台微信小程序商城构建全栈利用带后盾的IM即时通讯App 全程MVP手把手打造微信服务号+Yii2.0构建商城零碎全栈利用Web前后端破绽剖析与进攻Java SSM定制公众点评App后盾Vue2.0开发企业级挪动端音乐Web App再谈前后端分离式 手把手从0打造电商平台-前端开发Android热修复与插件化实际之路Laravel5.4疾速开发简书网站Vue2.0+Node.js+MongoDB全栈打造商城零碎Python操作三大支流数据库前端JavaScript面试技巧Java SSM疾速开发仿慕课网在线教育平台Android通用框架设计与残缺电商App开发Angular打造企业级合作平台极客学院WEB大前端工程师全套教程【原价98】Unity3D高级实战我的项目之方块跑酷最新版基于Spring Boot技术栈 博客零碎企业级前后端实战Web前端性能优化360大牛:全面解读PHP面试Python前后端拆散开发Vue+Django REST framework实战【原价7000】黑马2019最新软件测试培训教程 【完整版】【原价899】龙果学院—Java并发编程原理与实战(最新完整版)宋红康2019版—30天搞定Java核心技术【2019最新版】尚硅谷韩顺平Go语言外围编程Python外围根底【猿人部落】HTML&CSS外围根底JavaScript进阶核心技术剑指Java面试-Offer直通车2020全新升级版-Google资深工程师深度解说Go语言全方位深度分析PHP7底层源码uni-app 跨平台利用开发教程uni-app实战教程 - 《悦读》我的项目实战深度学习与TensorFlow 2入门实战教程全面把握MongoDB4.0 实现从小白达到人的变质Go实战仿百度云盘 实现企业级分布式云存储系统【完整版】【原价2188】腾讯课堂-Java架构班之BATJ企业面试课【慕课网待业班课程】Java 零根底入门【腾讯课堂原价2980】2019最新版-React Native零根底入门到项...GO从0到1实战微服务版抢红包零碎【腾讯课堂原价388】深度学习与PyTorch入门实战教程【腾讯课堂原价7480】Java互联网架构师零碎进阶课程(VIP)前端下一代开发语言TypeScript 从根底到axios实战【原价599】无人驾驶实战 [首次全面公开L4级别的全自动驾...2019版 微服务时代Spring Boot企业微信点餐零碎【最新版】Javascript 设计模式零碎解说与利用UI设计高级待业课,从零根底进阶UI设计师之路高并发&高性能 Go语言开发企业级抽奖我的项目three.js-打造微信爆款小游戏跳一跳【PHP待业班】PHP高级开发培训—企业级开发专题课程Python3实用编程技巧进阶基于 Spring Cloud 微服务架构下 广告零碎设计与实现(2020新版)【java待业班】2019从网页搭建入门JavaWeb算法大神带你玩转数据结构 从入门到精通【2019最新版】BAT大牛亲授 个性化举荐算法实战2021升级版Flutter从入门到进阶 实战携程网App(20章全)Go语言从入门到实战——扼要高效的Go语言实战指南Python服务端工程师待业面试领导Docker+Kubernetes(k8s)微服务容器化实际打造仿猫眼我的项目 以Dubbo为外围解锁微服务专为程序员设计的线性代数课程【2019最新版】20天Java开发大型电商零碎谷粒商城实战课程玩转Spring全家桶 一站通关Spring、Spring Boot与Spring Cloud【区块链实战】Golang公链我的项目实战 完整版(价值6800)【前端小白福利】HTML5+CSS3零根底实战特训班-待业班课程Go语言实战流媒体视频网站React16组件化+测试+全流程 实战“在线账本”我的项目Spring Cloud微服务架构我的项目实战——票务类电商网站大觅网Google大牛亲授-九章算法从 1 到 N 全面把握面试算法小白的福音:20小时疾速入门Go语言Python数据结构与算法教程Go语言开发分布式任务调度 轻松搞定高性能Crontab高等数学-学习算法/人工智能/大数据的第一步微信小程序进阶实战之分许可用开发JavaScript版 数据结构与算法带后盾的IM即时通讯App 全程MVP手把手打造React源码深度解析 高级前端工程师必备技能一站式学习Redis 从入门到高可用分布式实际ZooKeeper分布式专题与Dubbo微服务入门Java从单体到微服务打造房产销售平台RocketMQ核心技术精讲与高并发抗压实战【最新更新版】Python分布式爬虫打造搜索引擎Vue2.5开发去哪儿网App 从零根底入门到实战我的项目【2019更新版】Vue.js源码全方位深刻解析MySQL面试指南-中高级IT开发人员降职加薪的必备佳品!【2019更新版】新一代大数据计算引擎 Flink从入门到实战Java并发编程入门与高并发面试Java并发编程高阶技术 高性能并发框架源码解析与实战全流程开发 GO实战电商网站高并发秒杀零碎Google工程师亲授 Tensorflow2.0-入门到进阶Python爬虫工程师必学——App数据抓取实战【2019最新版】性能测试入门-Jmeter工具与监控全方位打造小白福音!零根底入门软件测试,首选必备课程Node.js 从零开发web server博客我的项目Vue全家桶+SSR+Koa2全栈开发美团网React全家桶+AntD 共享单车后盾管理系统开发Python3+TensorFlow 打造人脸识别智能小程序深度学习之神经网络(CNN/RNN/GAN) 算法原理+实战2019黑马JAVAEE57期根底班待业班【图灵VIP专属课堂】JAVA互联网架构师专题/分布式/高并发/...阿里新批发数据库设计与实战30个小时搞定Python网络爬虫(全套具体版)【新手入门圣经】亿级流量电商详情页零碎实战-缓存架构+高可用服务架构+微服务架构从零起步 零碎入门Python爬虫工程师WebRTC实时互动直播技术入门与实战 5G时代必备技能NLP实际TensorFlow打造聊天机器人Python零根底人工智能待业班Nginx外围常识100讲【2019最新版】Web协定详解与抓包实战——陶辉新手入门大数据 Hadoop根底与电商行为日志剖析Go语言外围36讲计算机根底——更适宜程序员的编程必备基础知识Angular8开发拼多多WebApp-从根底到我的项目实战Selenium3与Python3实战Web自动化测试框架前端要学的测试课 从Jest入门到TDD/BDD双实战微信小程序云开发-从0打造云音乐全栈小程序线程八大外围+Java并发底层原理精讲Zookeeper源码剖析一站式学习Java网络编程 全面了解BIO/NIO/AIOFFmpeg音视频核心技术精讲与实战面向未来微服务:Spring Cloud Alibaba从入门到进阶深度学习之指标检测罕用算法原理+实际精讲玩转算法系列--图论精讲 面试升职必备(Java版)企业级Android利用架构设计与开发辞别996 实现高效编程 缩小开发压力ElasticSearch+Spark 构建高相关性搜寻服务&千人千面举荐零碎百万级高并发WebRTC流媒体服务器设计与开发再学JavaScript ES(6-10)全版本语法大全Node.js-Koa2框架生态实战-从零模仿新浪微博Django入门到进阶-更适宜Python小白的零碎课程Django开发企业实战 面向待业/升职(中高级教程)入门挪动端混合开发 实战京东 APP图解+仿写 老手都能学懂的SpringBoot源码课前端全栈工程师精英班零根底入门前端开发工程师Go读书社区web开发与高性能架构优化编程必备根底-大话HTTP协定Linux外围技能与利用玩转Java并发工具,精通JUC,成为并发多面手Spark + ElasticSearch 构建电商用户标签零碎实现精准营销TypeScript 零碎入门到我的项目实战 趁早学习进步职场竞争力全流程开发 TP6.0实战高并发电商服务零碎Typescript + React 高仿 Antd 从零到一打造本人的组件库前端框架及我的项目面试-聚焦Vue、React、WebpackBAT资深工程师由浅入深剖析 Tp5&Tp6底层源码剑指Java自研框架,决胜Spring源码Jetpack开发短视频利用实战零根底入门 实战mpvue2.0多端小程序框架Spark进阶 大数据离线与实时我的项目实战剑指Java我的项目面试 助你顺利Offer编程必备根底-音视频小白零碎入门课uni-app入门到实战 以我的项目为导向 把握残缺开发流程Spark2.x+协同过滤算法,开发企业级个性化举荐零碎新版Kotlin从入门到精通专为程序员设计的低等数学课Kafka多维度零碎精讲,从入门到熟练掌握Java通用型领取+电商平台双系统实战基于GitHub App 深度解说Kotlin高级个性与框架设计分析Framework面试 冲击Android高级职位仿阿里系优酷网-企业级Go革新PHP我的项目踩坑避坑指北【完结】2020最新版React Native从入门到实战打造高质量上线AppJavaScript版数据结构与算法 轻松解决前端算法面试挪动端Python爬虫实战-2020版强力Django+杀手级xadmin开发在线教育网站 采纳 Python3.7全新开发【Go语言中文网】资深Go开发工程师第二期Python工程师Android工程师零根底入门 Python Web 自动化测试微业余—数据可视化把握高效数据可视化技法 完结2020升级版零碎学习Docker 践行DevOps理念2020升级版全面零碎Python3.8入门+进阶 (程序员必备第二语言)升级版Python Flask高级编程之从0到1开发《鱼书》精品我的项目微业余-Python爬虫工程师 - 3个月成为网络爬虫工程师零根底入门 全角度解读企业支流数据库MySQL8.0精讲Elastic-job + Quartz实现企业级定时工作支流技术栈的Restful API接口测试实战玩转热门框架 用企业级思维 开发通用够硬的大数据平台JavaScript玩转机器学习 打造你人生中的第一个AI我的项目混合开发入门 Vue联合Android/iOS开发仿京东我的项目AppVue全家桶实战 从零独立开发企业级电商零碎(收费降级Vue3.0)网易“白帽子黑客”训练营新版Nginx1.17体系化深度精讲 给开发和运维的刚需课程SparkSQL极速入门 整合Kudu实现广告业务数据分析深度解锁SpringCloud支流组件 一战解决微服务诸多难题Vue Element+Node.js开发企业通用治理后盾零碎React16.8+Next.js+Koa2开发Github全栈我的项目Python Flask疾速入门与进阶Spring Cloud微服务平安实战Electron+React+七牛云 实战跨平台桌面利用Java Web自动化测试 Selenium根底到企业理论利用(全新上线)React劲爆新个性Hooks 重构游览电商网站火车票PWANode.js仿知乎服务端-深刻了解RESTful APIPython主讲挪动端自动化测试框架Appium 从根底到我的项目实战React开发简书我的项目 从零根底入门到实战Web前端架构师Activiti6.0工作流引擎深度解析2021年最新 Java大型企业级我的项目 在线教育零碎实战全面系统学测试 从小白入门到实战待业2020 重学C++ 重构你的C++常识体系Spring Cloud + Vue 前后端拆散 开发企业级在线视频课程零碎大学计算机必修课新讲--编译原理+操作系统+图形学实战企业级我的项目 践行App重构之路Node.js+Koa2+MySQL打造前后端拆散精品我的项目《旧岛》利用Go优越的性能 设计与实现高性能企业级微服务网关ReactNative+TypeScript仿喜马拉雅开发AppPython3入门人工智能 把握机器学习+深度学习 晋升实战能力从零开始学调优-Java 全技术栈 性能调优 完结实践+实战 构建残缺JVM常识体系【完结】大前端(已完结)实战课程 Java企业级领取全家桶设计与实战 【已完结】JAVA互联网架构师专题/分布式/高并发/微服务【2020最新第三期】Activiti7精讲&Java通用型工作流开发实战疾速搞定前端技术一面 匹配大厂面试要求(升级版).Net Core 开发电商后端API 从0到精通吃透RESTful聚焦市场开发热门技术 手把手带你开发商业级社交AppSpringCloud+Vertx+Disruptor 金融业撮合交易系统实战前端性能优化--6大角度综合型优化计划开课吧web全栈架构师第16期(2020完结)微业余-职场人必学的Python技能课微业余-精通JAVA/高并发/微服务/分布式/中间件基于SpringCloud+Kubernetes ,微服务的容器化继续交付实战Kotlin开发AI语音助手App 后人一步放松挪动端AI时代倒退机会Java实操避坑指南 业务代码-整合框架-存储-缓存常见谬误详解Vue3.0(正式版) + TS 仿知乎专栏企业级我的项目【完结】微业余-uni-app实战仿微信app开发开课吧-Java企业级分布式架构师(2020最新)开课吧—web前端全栈开发(2020年最新)Kubernetes/K8s架构师实战集训营【2020最新】微信受权扫码点餐-新个性React16Spring Security + OAuth2 精讲 多场景打造企业级认证与受权 【 完结】分布式开发6大外围专题 把握企业级分布式我的项目计划【完结】Laravel重构企业级电商我的项目 全面强化职场外围竞争力新RabbitMQ精讲,我的项目驱动落地,分布式事务拔高Spark3大数据实时处理-Streaming+Structured Streaming 实战Vue3.0+TS打造企业级组件库 疾速把握Vue3企业理论利用PyTorch入门到进阶 实战计算机视觉与自然语言解决我的项目极客大学-前端进阶训练营【2020最新版】Java架构师成长直通车【完结】体系课-数据可视化入门到精通-打造前端差异化竞争力【完结】算法与数据结构体系课【完结】java全栈工程师:从java后端到全栈,高级电商全栈零碎大课【30周完结】Java工程师【2020版】前端工程师-2020版【32周完结】用 React.js+Egg.js 造轮子 全栈开发游览电商利用Spring Cloud散布式微服务实战,养成应答简单业务的综合技术能力协程原理从入门到精通 每个后端开发都须要把握的高性能开发技术 【完结】从入门到实战 进阶式把握Vue3残缺常识体系【完结】C语言系统化精讲 重塑你的编程思维 打造松软的开发根底 完结Java架构师-十项全能【34周完结】挪动端架构师 【20周完结】Go开发工程师:迎接回升风口,踏入蓝海行业!【完结】Go微服务入门到容器化实际,落地可观测的微服务电商我的项目【完结】人人都能学会数据分析【完结】大数据开发工程师算法面试专题课(Java版)【完结】高级Redis利用进阶课 一站式Redis解决方案【完结】Python全栈工程师2020升级版【完结】React17 零碎精讲 联合TS打造游览电商平台SpringBoot 在线协同办公小程序开发 全栈式我的项目实战React17+React Hook+TS4 最佳实际 仿 Jira 企业级我的项目【完结】迈向高级的Java面试解围课Android 应用程序构建实战+原理精讲毕设一课通 从开题到问难高效实现(含全栈我的项目)【完结】Kubernetes 入门到进阶实战算法训练营架构师训练营JAVA进阶训练营(2021最新版)GO进阶训练营【完结】python进阶训练营JavaEE在线待业班2.0Web前端架构师体系课-Go+Python双语言混合开发 盯紧技术先机 放松高薪时机笑傲Java面试:面霸修炼手册【完结】Flutter高级进阶实战 仿哔哩哔哩APPPython自动化测试开发实战 一门能待业的测试课Spring Boot + Vue3 前后端拆散 实战wiki知识库零碎首门程序员理财课 Python量化交易系统实战2021必修 首门CSS架构零碎精讲 实践+实战玩转蘑菇街【完结】Java异样与调优一站式解决方案Vue3.0高阶实战:开发高质量音乐Web app30小时疾速精通C++和外挂实战-大神MJ精选小马哥的 Java 我的项目实战营OpenCV入门到进阶:实战三大典型我的项目Go Web开发进阶我的项目实战(基于gin框架共81课时)Vue3+ElementPlus+Koa2 全栈开发后盾零碎Flink+ClickHouse 玩转企业级实时大数据开发《慕慕到家》家政小程序组件化进阶实战人人都要学的项目管理课Spring Cloud Alibaba 大型互联网畛域多场景最佳实际【完结】Kaggle比赛经典案例深度分析Java工程师高薪训练营【完结】Go 微服务实战 38 讲22讲通关Go语言LG-重学操作系统高并发 高性能 高可用 MySQL 实战uni-app实战直播app全栈开发极客大学-架构实战营|第0期深刻Vue3+TypeScript技术栈-coderwhy大神新课图灵学院JAVA高级架构师【第四期】|最新完结无密拉勾测试开发工程师训练营【享学课堂】Java互联网架构师零碎进阶课程(VIP)|最新三期|正课已完结Docker 系统性入门+进阶实际(2021最新版)从零打造微前端框架:实战“汽车资讯平台”我的项目新版 Spring Boot双版本(1.5/2.1) 打造企业级微信点餐零碎【2021最新升级版】Java短视频小程序开发 全栈式实战我的项目【2021最新升级版】Vite 从入门到精通,玩转新时代前端构建法令Unity 全流程开发热门游戏BallSort,助力迈入游戏高薪畛域Spring Cloud / Alibaba 微服务架构实战【黑马精品】Java架构师实战训练营轻松实现Rust零碎入门,实战编译器开发前端支流布局零碎进阶与实战[完结无密]马士兵-大数据全栈工程师大数据精英一班|2021最新Spark+ES+ClickHouse 构建DMP用户画像升级TypeScript高手,成为热门的前端开发人才【完结】高级爬虫实战-零碎把握破解反爬技能 挑战高薪开课吧-门徒打算算法班SpringBoot+Vue3 我的项目实战,打造企业级在线办公零碎黑马-软件测试V4.0 |2021年|完结无秘马哥高端Go语言百万并发高薪班/微服务/分布式高可用/Go高并发拉钩-Java工程师待业急训营极客-产品经理训练营【13章完结】贪婪学院-举荐零碎算法工程师造就打算Dubbo 3 深度分析 - 透过源码意识你开课吧-自然语言解决(NLP)-导师制名企实训班四期极客工夫-云原生训练营Go高级工程师实战营零碎入门深度学习,直击算法工程师2021年最新 Java大型企业级我的项目 在线教育零碎实战大厂学苑 -RPC框架外围源码深度解析九章算法班 2021 版基于Vue3最新规范,实现后盾前端综合解决方案后端校招面试突击课,4年本科根底大复盘 助力进大厂2021前端校招直通车,实现Offer零距离React 配置化+Serverless 开发集体博客八斗大数据20期开课吧-并发编程与JVM畛域进阶打算【VIP课程】极客工夫-Go进阶训练营|全新降级第4期WebRTC源码级深度解析机器学习中的概率统计利用实际Python操作三大支流数据库 实战网易新闻客户端黑马-Linux云计算+运维开发+全新降级V3版本|完结无秘基于Vue3+Vite+TS,二次封装element-plus业务组件Kali零根底 Web 平安浸透工程师实战待业班|2021最新版开课吧-Web全栈架构师23期|完结无密开课吧-Kali平安高级工程师进阶班|2021最新C/C++气象数据中心实战,手把手教你做工业级我的项目Shell 高阶开发实战DDD(畛域驱动设计)思维解读及优良实际网易微业余-AI工程师-自然语言解决Spring 5实战开发及新个性精讲Taro@3.3.3最新版本开发企业级出行我的项目基于 React + Redux/Mobx 搞定简单我的项目状态治理开课吧-大数据开发工程师|2021最新完结无密SpringBoot 2.x 实战仿B站高性能后端我的项目咕泡云课堂-P6:Java互联网高级架构师(SVIP涨薪班)零碎入门云计算服务,我的项目上云最佳实际玩转自动化运维全流程全局视角零碎学习《举荐零碎》,实战中晋升竞争力物联网根底入门,实战可落地的 AIoT 我的项目破解JavaScript高级玩法拉钩算法突击训练营-完结无密Android面试超级攻略,全面攻破技术疑难及面试痛点珠峰前端架构师造就打算2021年版-完结无密2周刷完100道前端优质面试真题【马sbVIP课程】Java高级互联网架构师【1-7班合集】2022最新网易微业余测试工程师-打造最业余的测试人柠檬班-python自动化测试第35期-2021最新完结马士兵-Python全栈工程师 图解Python语法-2022最新完结拉钩教育-大前端高薪训练营 NEXT打算|定制将来挪动互联网高级开发正式课VIP课程-码牛学院【第二期】完结无密2021全新升级版-若泽数据Spark+Flink全栈训练营(高级班)拉钩教育-数据分析实战训练营完结无密尚硅谷-java高级工程师(2022最新)2021助力高薪-拉钩产品经理高薪训练营C#速成指南:从入门到进阶,实战WPF与Unity3D开发Vue3+Nuxt3打造SSR网站利用,0到1实现服务端渲染构建千万级高可用企业级Node.js利用测试必学:探秘大厂全链路品质保障体系【体系课】吃透前端工程化,大厂级实战我的项目以战带练拉钩教育-大数据高薪训练营2022最新版【扔物线】Android 高级开发瓶颈冲破系列课-第五期云原生利用架构设计与开发实战Next.js+React+Node零碎实战,搞定SSR服务器渲染开课吧-WEB全栈架构师进阶指南(30期)完结无密奈学教育-P8百万 Java架构师3期(完结无密)八斗学院3期-人工智能|2021年完结无密极课工夫-大数据训练营2021最新完结【华测教育】年薪50W-高级测试开发全栈系列课优良职场人必修课-职场心理学, 助你走出内耗陷阱云原生+边缘计算+KubeEdge,打造智能边缘治理平台基于 Vue3 ,打造前台+中台通用提效解决方案深刻Go底层原理,重写Redis中间件实战给前端同学的设计模式精讲课黑马-前端V7.6-价值9980元-2022年最新完结无秘拉钩教育-数据分析实战训练营|完结无密奈学教育-Java资深研发工程师9期|2022最新完结无密数据分析+Py全栈+爬虫+Ai=python全能工程师-挑战年薪30万开课吧-数据分析高薪造就打算精英班-30期|完结无密JAVA互联网架构师专题/分布式/高并发/微服务|2022最新第五期百战程序员-JavaEE高薪待业班2022年最新完结开课吧-人工智能外围能力造就打算 -007期完结无密Node.js工程师养成打算【微体系】多端全栈我的项目实战:商业级代驾全流程落地基于 Flutter 3.x 实战跨平台混合开发某课网-前端工程师2022版|最新完结无密拉钩-算法突击特训营3期|2022最新完结无密本文由博客一文多发平台 OpenWrite 公布!

July 16, 2022 · 2 min · jiezi

关于go:golang-用channel做锁

当chanel的容量为1的时候能够作为锁来实现一些原子操作 比方 咱们想实现一个+1的协程 还要保障原子性 就能够这样: package mainimport ( "fmt" "time")func main() { test_chan := make(chan bool, 1) //这里容量设为1 var x int for i := 0; i < 1000; i++ { go rise(test_chan, &x) } time.Sleep(time.Second) //用mutex更佳 fmt.Println("the value of x is : ", x)}//因为要扭转原来x的值 所以这里要应用指针//因为信道的容量为1 所以写数据后 进行原子操作 而后立马数据推出去func rise(ch chan bool, x *int) { ch <- true *x = *x + 1 <-ch}运行后果: the value of x is : 1000 ...

July 16, 2022 · 1 min · jiezi

关于go:Go-119要来了看看都有哪些变化第4篇

前言Go官网团队在2022.06.11公布了Go 1.19 Beta 1版本,Go 1.19的正式release版本预计会在往年8月份公布。 让咱们先睹为快,看看Go 1.19给咱们带来了哪些变动。 这是Go 1.19版本更新内容详解的第4篇,欢送大家关注公众号,及时获取本系列最新更新。 第1篇次要波及Go泛型的改变、Go内存模型和原子操作的优化,原文链接:Go 1.19版本变更内容第1篇。 第2篇次要波及Go文档正文(doc comments)、编译束缚(build constraint)以及Go命令的批改,原文链接:Go 1.19版本变更内容第2篇。 第3篇次要波及Go运行时、编译器、汇编器和链接器方面的改变和优化,原文链接:Go 1.19版本变更内容第3篇。 Go 1.19公布清单和Go 1.18相比,改变绝对较小,次要波及语言(Language)、内存模型(Memory Model)、可移植性(Ports)、Go Tool工具链、运行时(Runtime)、编译器(Compiler)、汇编器(Assembler)、链接器(Linker)和外围库(Core library)等方面的优化。 本文重点介绍Go 1.19版本在外围库(Core library)方面的变动。 新的原子类型(New atomic types)sync/atomic包里当初定义了新的类型: Bool, Int32, Int64, Uint32, Uint64, Uintptr, and Pointer。 这些新的类型定义了相应的原子办法,要批改或者读取这些类型的变量的值就必须应用该类型的原子办法,这样能够防止误操作。 type Bool struct { // contains filtered or unexported fields}func (x *Bool) CompareAndSwap(old, new bool) (swapped bool)func (x *Bool) Load() boolfunc (x *Bool) Store(val bool)func (x *Bool) Swap(new bool) (old bool)比方下面的sync/atomic包里的Bool类型就有4个原子办法,要读取或者批改atomic.Bool类型的变量的值就要应用这4个办法。 ...

July 16, 2022 · 2 min · jiezi

关于go:40倍提升详解-JuiceFS-元数据备份恢复性能优化之路

JuiceFS 反对多种元数据存储引擎,且各引擎外部的数据管理格局各有不同。为了便于管理,JuiceFS 自 0.15.2 版本提供了 dump 命令容许将所有元数据以对立格局写入到 JSON 文件进行备份。同时,JuiceFS 也提供了 load 命令,容许将备份复原或迁徙到任意元数据存储引擎。命令的详细信息能够参考这里。根本用法: $ juicefs dump redis://192.168.1.6:6379/1 meta.json$ juicefs load redis://192.168.1.6:6379/2 meta.json该性能自 0.15.2 版本公布后到当初 v1.0 RC2 经验了 3 次比拟大的优化,性能失去了几十倍的晋升, 咱们次要在以下三个方向做了优化: 减小数据处理的的粒度:通过将大对象拆分为小对象解决,能够大幅缩小内存的占用。另外拆分还有利于做细粒度的并发解决。缩小 io 的操作次数:应用 pipline 来批量发送申请缩小网络 io 的耗时。剖析零碎中的耗时瓶颈:串行改为并行,进步 cpu 利用率。这些优化思路比拟典型,对于相似网络申请比拟多的场景具备肯定的通用性,所以咱们心愿分享下咱们的具体实际,心愿能给大家肯定的启发。 元数据格式在分享 dump load 性能之前,咱们先看下文件系统长什么样,如下图所示,文件系统是一个树形构造,顶层根目录,根目录下有子目录或者文件,子目录上面又有子目录或者文件。所以如果想要晓得文件系统外面的所有文件和文件夹,只须要遍历这颗树就行了。 理解了文件系统的特点后,咱们再看 JuiceFS 的元数据存储的特点,JuiceFS 元数据的存储次要是几张不同的 hash 表,每个 hash 表的 key 都是单个文件的 inode ,而inode 信息能够通过文件树的遍历失去。所以只须要遍历文件树拿到所有的inode,再依据 inode 为索引就能够拿到所有的元数据了。另外为了浏览性更好,并且保留本来的文件系统的树形构造,咱们将导出的格局定为了 json。将下面示例文件系统 dump 进去的 json 文件如下所示,其中 hardLink 为 file 的硬链接 json 内容: ...

July 15, 2022 · 3 min · jiezi

关于go:gozero微服务实战系列十一大结局

本篇是整个系列的最初一篇了,原本打算在系列的最初一两篇写一下对于k8s部署相干的内容,在构思的过程中感觉本人对k8s常识的把握还很有余,在本人没有了解把握的前提下我感觉也很难写出本人称心的文章,大家看了可能也会感觉内容没有干货。我最近也在学习k8s的一些最佳实际以及浏览k8s的源码,期待时机成熟的时候可能会思考独自写一个k8s实战系列文章。 内容回顾上面列出了整个系列的每篇文章,这个系列文章的次要特点是贴近实在的开发场景,并针对高并发申请以及常见问题进行优化,文章的内容也是循序渐进的,先是介绍了我的项目的背景,接着进行服务的拆分,拆分完服务进行API的定义和表构造的设计,这和咱们理论在公司中的开发流程是相似的,紧接着就是做一些数据库的CRUD基本操作,前面用三篇文章来解说了缓存,因为缓存是高并发的根底,没有缓存高并发零碎就无从谈起,缓存次要是应答高并发的读,接下来又用两篇文章来对高并发的写进行优化,最初通过分布式事务保障为服务间的数据一致性。如果大家可能对每一篇文章都能了解透彻,我感觉对于工作中的绝大多数场景都能轻松应答。 对于文章配套的示例代码并没有写的很欠缺,有几点起因,一是商城的性能点十分多,很难把所有的逻辑都笼罩到;二是少数都是反复的业务逻辑,只有大家把握了外围的示例代码,其余的业务逻辑能够本人把代码down下来进行补充欠缺,这样我感觉才会提高。如果有不了解的中央大家能够在社区群中问我,每个社区群都能够找到我。 go-zero微服务实战系列(一、开篇) go-zero微服务实战系列(二、服务拆分) go-zero微服务实战系列(三、API定义和表结构设计) go-zero微服务实战系列(四、CRUD热身) go-zero微服务实战系列(五、缓存代码怎么写) go-zero微服务实战系列(六、缓存一致性保障) go-zero微服务实战系列(七、申请量这么高该如何优化) go-zero微服务实战系列(八、如何解决每秒上万次的下单申请) go-zero微服务实战系列(九、极致优化秒杀性能) go-zero微服务实战系列(十、分布式事务如何实现) 单元测试软件测试由单元测试开始(unit test)。更简单的测试都是在单元测试之上进行的。如下所示测试的层级模型: 单元测试(unit test)是最小、最简略的软件测试模式、这些测试用来评估某一个独立的软件单元,比方一个类,或者一个函数的正确性。这些测试不思考蕴含该软件单元的整体零碎的正确定。单元测试同时也是一种标准,用来保障某个函数或者模块完全符合系统对其的行为要求。单元测试常常被用来引入测试驱动开发的概念。 go test工具go语言的测试依赖go test工具,它是一个依照肯定约定和组织的测试代码的驱动程序。在包目录内,所有以_test.go为后缀的源代码文件都是 go test 测试的一部分,不会被go build编译到最终的可执行文件。 在*_test.go文件中有三种类型的函数,单元测试函数、基准测试函数和示例函数: 类型格局作用测试复数函数名前缀为Test测试程序的一些逻辑行为是否正确基准函数函数名前缀为Benchmark测试函数的性能示例函数函数名前缀为Example提供示例go test会遍历所有*_test.go文件中合乎上述命名规定的函数,而后生成一个长期的main包用于调用相应的测试函数。 单测格局每个测试函数必须导入testing包,测试函数的根本格局如下: func TestName(t *testing.T) { // ......}测试函数的名字必须以Test结尾,可选的后缀名必须以大写字母结尾,示例如下: func TestDo(t *testing.T) { //...... }func TestWrite(t *testing.T) { // ...... }testing.T 用于报告测试失败和附加的日志信息,领有的次要办法如下: Name() stringFail()Failed() boolFailNow()logDepth(s string, depth int)Log(args ...any)Logf(format string, args ...any)Error(args ...any)Errorf(format string, args ...any)Fatal(args ...any)Fatalf(format string, args ...any)Skip(args ...any)Skipf(format string, args ...any)SkipNow()Skipped() boolHelper()Cleanup(f func())Setenv(key string, value string)简略示例在这个门路下lebron/apps/order/rpc/internal/logic/createorderlogic.go:44 有一个生成订单id的函数,函数如下: ...

July 15, 2022 · 2 min · jiezi