Go语言入门记录:从channel的池应用、sync的Pool、benchmark、反射reflect、json处理、http、性能分析和一些编程习惯

  1. channel的一对一会阻塞,添加buffer不会阻塞。
func GetResponse() string {// 如果是这一句,确实只返回了1个,但是其他几个都阻塞了,浪费协程,浪费服务器资源,容易造成泄露等安全问题// ch := make(chan string)// 如果用下面这句,每个协程都只管往channel中传数据,传完就结束ch := make(chan string, 10)for i := 0; i < 10; i++ {go func(idx int) {time.Sleep(time.Millisecond * 10)ch <- "response from " + strconv.Itoa(idx)}(i)}return <-ch// 如果要返回所有任务的结果,就在这里for循环拼接拿到的所有<-ch数据
}func TestGetAnyResponse(t *testing.T) {fmt.Println("before: goroutine number is ", runtime.NumGoroutine()) // 2fmt.Println(GetResponse())time.Sleep(time.Second * 1)fmt.Println("afer: goroutine number is ", runtime.NumGoroutine()) // 第一种输出11,第二种输出2
}
  1. buffered Channel实现对象池。

type ReuseableObj struct {num int
}
type ObjPool struct {bufferChan chan *ReuseableObj
}func NewObjPool(num int) *ObjPool {objPool := ObjPool{}objPool.bufferChan = make(chan *ReuseableObj, num)for i := 0; i < num; i++ {rObj := ReuseableObj{num: i}objPool.bufferChan <- &rObj}return &objPool
}func (p *ObjPool) GetObj(timeout time.Duration) (*ReuseableObj, error) {select {case ret := <-p.bufferChan:return ret, nildefault:return nil, errors.New("time out")}
}func (p *ObjPool) ReleaseObj(obj *ReuseableObj) error {select {case p.bufferChan <- obj:return nildefault:return errors.New("overflow")}
}func TestChannelPool(t *testing.T) {objPool := NewObjPool(10)for i := 0; i < 20; i++ {if v, err := objPool.GetObj(time.Second * 1); err != nil {fmt.Println(err)} else {fmt.Printf("adderss is %x\n", unsafe.Pointer(&v))fmt.Println(v.num)if msg := objPool.ReleaseObj(v); msg != nil {fmt.Println(msg)}}}
}
  1. sync.Pool的介绍。
  • 获取时先去私有对象中获取,如果不存在就在相同Processor中的共享池中获取,如果还没有,则去其他Processor中去获取。
  • 存放时,如果私有对象不存在,就放在私有对象中,如果存在就放在Processor中。
  • 它其实不能当做对象池去用,因为每次GC都会清空sync.Pool中所有对象,所以这就是为什么上面我们用buffered channel当做对象池来用。
  • 那如果被GC清空了,还要获取的话,怎么办?sync.Pool就会重新初始化一下。
  • 其实,每次如果没有对象,则会开启New方法初始化一下,所以获取的就是999,这里暂时不需要断言了,因为返回的是any
  • 所以,它不适合用来管理自己要定义生命周期的池,因为系统GC不可控。
func TestSyncPool(t *testing.T) {pool := &sync.Pool{New: func() any {fmt.Println("create...")return 999},}t.Log(pool.Get()) // 999t.Log(pool.Get()) // 999t.Log(pool.Get()) // 999pool.Put(100)t.Log(pool.Get()) // 100t.Log(pool.Get()) // 999pool.Put(98)pool.Put(99)t.Log(pool.Get()) //98t.Log(pool.Get()) //99pool.Put(100)runtime.GC()t.Log(pool.Get()) //999
}
  1. 我们之前一直在用单元测试在写代码,正常保证文件名_test.go和方法Testxxx即可。在测试代码中如果用t.Fail("xxx")代码其实还会一直执行下去;如果用t.Fatal("xxx")则代码直接中断了。当然还可以借助第三方包进行断言操作。

  2. benchmark和test使用类似,有自己定义的一套语言,如下。

func BenchmarkConcatString(b *testing.B) {b.ResetTimer()for i := 0; i < 10000; i++ {}b.StopTimer()
}
// 输出信息包括一共运行次数,每次op用的时间,每次op用到的allocs次数,可以用来比较查找问题
BenchmarkConcatString
BenchmarkConcatString-16
1000000000             0 B/op          0 allocs/op

还有一些BDD的框架,比如goconvey

  1. 使用反射编程。主要是是reflect的几个方法,主要的是如果是获取变量值或者调用方法则后面是ValueOf(),如果是获取信息的则用TypeOf()
func TestReflect(t *testing.T) {c := &Course{name: "math", score: 100}// 直接访问成员变量:ValueOf + FieldByNamet.Log(reflect.ValueOf(*c).FieldByName("score")) //100t.Log(c)                                        //&{math 100}// 访问成员方法:ValueOf + MethodByNamereflect.ValueOf(c).MethodByName("UpdateScore").Call([]reflect.Value{reflect.ValueOf(60)})t.Log(c) //&{math 60}// 获取成员变量的一些信息:TypeOf + FieldByNameif nameField, ok := reflect.TypeOf(*c).FieldByName("name"); ok {t.Log(nameField.Tag.Get("format")) // haha} else {t.Log("get error")}if nameField1, ok := reflect.TypeOf(*c).FieldByName("score"); ok {t.Log(nameField1.Type) // int} else {t.Log("get error")}
}

有一个小知识点,我们的map是不能相互比较的,但可通过reflect.DeepEqual(map1, map2)实现比较。

func TestCmpMap(t *testing.T) {map1 := map[int]string{1: "one", 2: "two"}map2 := map[int]string{1: "one", 2: "two"}//t.Log(map1 == map2)t.Log(reflect.DeepEqual(map1, map2)) //true
}

反射编程灵活性高,但性能有损耗,代码可读性也会降低。

  1. unsafe尽量不要使用,除非有些地方必要要使用这种变量类型。

  2. 自带的json解析不如第三方解析包,比如easyjson。但我尝试了一下,还是放弃easyjson,有些麻烦,写个文件,然后使用命令生成个特殊文件里面自动生成好了针对这个对象的marshal等方法,意味着可以直接调用。我还是乖乖使用自带的吧。

type Student struct {Name string `json:"name"`Age  int    `json:"age"`
}var studentStr = `{"name": "Eric","age": 18
}`func TestJson(t *testing.T) {s := new(Student)if err := json.Unmarshal([]byte(studentStr), s); err != nil {t.Log(err)} else {t.Log(s.Name) //Eric}if data, err := json.Marshal(s); err != nil {t.Log(err)} else {t.Log(string(data)) //{"name":"Eric","age":18},data是个bytes[]需要转换}
}func TestEnCoderAndDecoder(t *testing.T) {s := new(Student)decoder := json.NewDecoder(strings.NewReader(studentStr))if err := decoder.Decode(s); err != nil {t.Log(err)} else {t.Log(s.Name) //Eric}encoder := json.NewEncoder(os.Stdout)if err := encoder.Encode(s); err != nil { // 直接输出了{"name":"Eric","age":18}t.Log(err)}
}
  1. 用内置的http可以开启服务。
package mainimport ("fmt""net/http"
)func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "hello http...")})http.HandleFunc("/getName", func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Eric"))})http.ListenAndServe(":9090", nil)
}

可以使用第三方路由。

// 安装
go get -u github.com/julienschmidt/httprouter
// 使用GET和POST以及接收参数,POST可以分别接收Form参数和Json参数都是从Request中获取
package mainimport ("encoding/json""fmt""log""net/http""github.com/julienschmidt/httprouter"
)func GetByIdFunc(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {fmt.Fprint(w, "hello http...")
}func GetByNameFunc(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {w.Write([]byte("hello " + ps.ByName("name")))
}type User struct {Id   stringName string
}func main() {router := httprouter.New()router.GET("/", GetByIdFunc)router.GET("/getByName/:name", GetByNameFunc)router.POST("/submitForm", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {r.ParseForm()w.Write([]byte("hello id:" + r.Form.Get("id") + ";name:" + r.Form.Get("name")))})router.POST("/submitJson", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {content := make([]byte, r.ContentLength)r.Body.Read(content)user := new(User)if err := json.Unmarshal(content, user); err == nil {w.Write([]byte("hello id:" + user.Id + ";name:" + user.Name))} else {fmt.Print(err)w.Write([]byte("error happened"))}})log.Fatal(http.ListenAndServe(":9090", router))
}
  1. 性能分析。
  • 性能分析通过一些内置工具和第三方工具来分析pprofprofilegraphviz,还可以通过web界面查看。具体参考GO 性能分析。
  • 一些常用指标比如wall timeCPU timeBlock timeMemory allocationGC times等等。
  • 性能差的原因之一,有可能是代码中使用了不恰当的锁。
  1. 编程习惯。
  • 复杂对象(比如数组或者结构体)尽量传递引用。影响系统GC。
  • 初始化时就制定合适的容器大小,避免自动扩容。
  • string拼接,有个strings.Builder。
func TestStringBuilder(t *testing.T) {var sb strings.Buildersb.WriteString("Hi,")sb.WriteString("Eric")t.Log(sb.String()) //Hi,Eric
}
  • 注意僵尸进程
  • 考虑使用池优化资源使用
  • 不要害怕错误,尽早抛出错误,给出回应

入门之路结束!切换进阶之路!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/64962.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp项目实战系列(2):新建项目,项目搭建,微信开发工具的配置

目录 系列文章目录uniapp项目实战系列(1)&#xff1a;导入数据库&#xff0c;启动后端服务&#xff0c;开启代码托管&#xff08;点击跳转&#xff09;1.新建项目2.托管项目的操作&#xff1a;&#xff08;无勾选托管项目可无视&#xff09;3.项目编译预览3.1游览器编译3.2微信…

【数据结构与算法篇】手撕八大排序算法之交换排序

​&#x1f47b;内容专栏&#xff1a; 《数据结构与算法篇》 &#x1f428;本文概括&#xff1a;常见交换排序包括冒泡排序与快速排序&#xff0c;本篇讲述冒泡排序与快速排序的思想及实现、复杂度分析。 &#x1f43c;本文作者&#xff1a; 花 蝶 &#x1f438;发布时间&#…

Darshan日志分析

标头 darshan-parser 输出的开头显示了有关作业的总体信息的摘要。还可以使用–perf、–file或–total命令行选项生成其他作业级别摘要信息。 darshan log version&#xff1a;Darshan 日志文件的内部版本号。compression method&#xff1a;压缩方法。exe&#xff1a;生成日志…

skywalking agent监控java服务

一、前言 skywalking agent可以监控的服务类型有多种&#xff0c;python、go、java、nodejs服务等都可以监控&#xff0c;现在通过java服务来演示skywalking agent的使用&#xff0c;并且是使用容器的方式实现 二、部署skywalking agent监控 需要注意&#xff0c;skywalking…

Django报错:SystemCheckError: System check identified some issues解决办法

今天练习django自定义标签时&#xff0c;一开始在APPbook中写了自定义标签book_tags.py 测试成功&#xff0c;之后新建了一个APPblogs&#xff0c;测试在blogs中创建模板使用自定义标签&#xff0c;于是直接把book/templatetags包直接赋值到blogs目录里。在页面里加载自定义标…

数据分析基础-数据可视化学习笔记06-交互架构

互动与 可视化 对视觉表⽰进⾏操作 视觉分析的可视化应有助于对视觉表⽰数据的操作 ⼀系列反馈回路 概述 放⼤/缩⼩ 选择 筛选 查找相关信息 促进数据空间的探索。 互动类型 选择和操作 直接处理数据的视觉表⽰。 探索与导航 理解并⾛过视觉呈现的空间。 选择和…

K8s简介之什么是K8s

目录 1.概述 2.什么是容器引擎&#xff1f; 3.什么是容器 4.什么是容器编排&#xff1f; 5.容器编排工具 6.到底什么是K8s? 7.为什么市场推荐K8s 8.K8s架构 9.K8s组件 Pods API 服务器 调度器 控制器管理器 Etcd 节点 Kubelet Kube代理 Kubectl 1.概述 Kub…

通过这 5 项 ChatGPT 创新增强您的见解

为什么绝大多数的人还不会使用chatGPT来提高工作效能&#xff1f;根本原因就在还不会循序渐进的发问与chatGPT互动。本文总结了5个独特的chatGPT提示&#xff0c;可以帮助您更好地与Chat GPT进行交流&#xff0c;以获得更清晰的信息、额外的信息和见解。 澄清假设和限制 用5种提…

vcruntime140_1.dll丢失的三个修复方法,【vcruntime140_1修复工具下载】

大家好&#xff01;今天&#xff0c;我将为大家介绍一个关于计算机vcruntime140_1.dll丢失的问题。在我们的日常生活和学习中&#xff0c;计算机出现问题是常有的事情。有时候&#xff0c;我们可能会遇到一些令人头疼的问题&#xff0c;比如vcruntime140_1.dll丢失。那么&#…

C盘清理 “ProgramData\Microsoft\Search“ 文件夹过大

修改索引存放位置 进入控制面板->查找方式改成大图标&#xff0c; 选择索引选项 进入高级 填写新的索引位置 删除C盘索引信息 删除C:\ProgramData\Microsoft\Search\Data\Applications 下面的文件夹 如果报索引正在使用&#xff0c;参照第一步替换索引位置。关闭索引

stable diffusion实践操作-hypernetworks

系列文章目录 本文专门开一节写hypernetworks的内容&#xff0c;在看之前&#xff0c;可以同步关注&#xff1a; stable diffusion实践操作 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、h…

TDengine函数大全-聚合函数

以下内容来自 TDengine 官方文档 及 GitHub 内容 。 以下所有示例基于 TDengine 3.1.0.3 TDengine函数大全 1.数学函数 2.字符串函数 3.转换函数 4.时间和日期函数 5.聚合函数 6.选择函数 7.时序数据库特有函数 8.系统函数 聚合函数 TDengine函数大全APERCENTILEAVGCOUNTELAPS…

conda创建python虚拟环境

1.查看当前存在那些虚拟环境 conda env list conda info -e 2.conda安装虚拟环境 conda create -n my_env_name python3.6 2.1在anaconda下改变python版本 当前3.7 安装3.7 conda create -n py37 python3.7 conda activate py37 conda create -n py37 python3.7conda a…

IDM2024Internet Download Manager下载器最新版本

IDM&#xff08;Internet Download Manager&#xff09;下载器主窗口的左侧是下载类别的分类&#xff0c;提供了分类功能来组织和管理文件。如果不需要它&#xff0c;可以删除“分类”窗口&#xff0c;并且在下载文件时不选择任何分类。 每个下载类别都有一个名称&#xff0c;…

php中识别url被篡改并阻止访问的实现方式是什么

在 PHP 中&#xff0c;可以通过多种方式来识别并阻止 URL 被篡改的访问。以下是一些常见的方法&#xff1a; 基本身份验证&#xff1a;使用 PHP 的 $_SERVER[PHP_AUTH_USER] 和 $_SERVER[PHP_AUTH_PW] 变量可以实施基本的 HTTP 身份验证。在访问受保护的页面之前&#xff0c;可…

路由器的简单概述(详细理解+实例精讲)

系列文章目录 华为数通学习&#xff08;4&#xff09; 目录 系列文章目录 华为数通学习&#xff08;4&#xff09; 前言 一&#xff0c;网段间通信 二&#xff0c;路由器的基本特点 三&#xff0c;路由信息介绍 四&#xff0c;路由表 五&#xff0c;路由表的来源有哪些…

linux安装docker全过程

3. 第二步&#xff1a;设置docker的存储库。就两条命令&#xff0c;我们直接执行就好。 ​ sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo ​​ 4. 安装docker engine和docker-compose。 执行命…

IP地址、网关、网络/主机号、子网掩码关系

一、IP地址 IP地址组成 IP地址分为两个部分&#xff1a;网络号和主机号 &#xff08;1&#xff09;网络号:标识网段&#xff0c;保证相互连接的两个网段具有不同的标识。 &#xff08;2&#xff09;主机号:标识主机&#xff0c;同一网段内&#xff0c;主机之间具有相同的网…

AttributeError: ‘NoneType‘ object has no attribute ‘_free_weak_ref‘

AttributeError: NoneType object has no attribute _free_weak_ref yolov5训练时报错&#xff1a; AttributeError: ‘NoneType‘ object has no attribute ‘_free_weak_ref‘ 问题解决&#xff1a; 降低pytorch版本。 之前使用的是1.11.3&#xff0c;降低成1.10.2 卸载之前的…

WPF .NET 7.0学习整理(一)

参照文档进行不系统的整理&#xff0c;看到那写到那O.o 依赖属性 DependencyProperty&#xff1a;使用专有字段支持属性的标准模式的替代方法。 DependencyObject&#xff1a;定义了可以注册和拥有依赖属性的基类。 public static readonly DependencyProperty IsSpinningPr…