左耳听风_108_107_Go编程模式切片接口时间和性能
你好,我是陈浩网名做耳朵house.今天呢是我们的第一节课,我先带你学习一下go语言编程模式的一些基本技术和要点。
那了解了这些内容之后啊,你就可以更轻松的掌握go语言编程了。
其中呢主要包括数组切片的一些小坑、接口、编程以及时间和程序运行性能相关的内容。
话不多说啊,我们直接开始。
首先我来介绍一下,slice中文翻译呢叫做切片。
在构语言里面这个东西它不是数组组,而是一个结构体。
它的定义呢,我在文稿中给你了那一个空le slice表现是什么样的呢?我们可以看一下文章中这张图,熟悉c和c加加的同学呢一定会知道,在结构体里面用数组指针呢会有一个问题,就是数据啊会发生共享。
我们来看一看slice的一些操作代码呢,在文章里我来解释一下这段代码。
首先呢我创建了一个slice,叫做负,它的长度和容量呢都是五。
然后呢我对负所指向的数组中索引为三和四的元素啊进行赋值。
最后呢我对负五做切片赋值给把在修改,把里面索引为一的元素。
那为了方便你理解啊,我还画了一张图,你可以去文稿中看一下。
从这张图片中呢,我们可以看到,因为负合坝的内存是共享的,所以负合坝对数组内容的修改都会影响到对方。
那接下来呢我再来讲一个数据操作,append的示例代码呢在文稿里。
在这段代码中呢,我把a里面从一到十六这段切片啊付给b那这个时候呢a和b的内存空间啊是共享的。
然后呢我对a做了一个append的操作,那这个操作呢会让a重新分配内存。
那这样呢就会导致a和b啊不再共享。
就像文章里这张图表示的这样。
那么从这张图呢你会发现appen的操作让a的容量呢变成六十四,而长度呢是三十三。
那这里呢你需要重点注意一下apppad这个函数啊,在cap不够用的时候,就会重新分配内存,以扩大容量。
呃,如果够用啊,就不会重新分配内存了。
我们再来看一个例子,代码呢同样在文章里。
在这个例子中呢,DIR一和DR二共享内存呃,虽然DI二一有一个pand操作,但是因为cape足够,于是数据呢就扩展到了DI二二的空间。
文章里呢有一张示意图,记得看一下,那要解决这个问题啊,我们只需要修改一行代码,就是把pass去切片,复制给DRR一这一句啊增加一个self index的参数。
那新的代码呢使用了full slice expression,最后一个参数呢叫做limited capacity,于是后续的pad操作就会重新分配内存。
那讲完了slice再聊一聊深度比较。
当我们复制一个对象的时候啊,这个对象可以是内建的数据类型、数组结构体,还有map等等。
那其中在复制结构体的时候啊,如果我们需要比较两个结构体中的数据是否相同,那就要使用深度比较,而不只是简单的做浅度比较。
这里啊需要使用到反射reflect点,deep equal.我在文章里呢列了几个例子,下面呢我们来谈一谈接口编程。
文章里啊有一段代码里面呢有两个方法,它们都是要输出一个结构体。
那其中一个呢使用了一个函数,而另一个呢使用了一个成员函数。
那你更喜欢哪种方式在构语原理啊,使用成员函数的方式叫做receiver,这种方式呢是一种封装。
因为print person本来就是和person强耦合的,所以理应放在一起。
更重要的是这种方式呢可以进行接口编程。
那对于接口编程来说啊,也算是一种抽象,主要呢是用在多肽这个技术呢。
我在构元简介的上篇街苦与与多态中讲过,你可以点击文稿里的链接啊查看一下。
在这里呢我想讲一讲另外一个购源接口的编程模式。
文章里呢同样有一段代码,从代码中呢我们可以看到我们使用了一个叫做printable的接口,而country和city啊都实现了接口方法,print spring把自己输出来。
但是呢这些代码都是一样的,能不能省掉呢?其实呢我们可以使用结构体嵌入的方式来完成这个事儿。
我们可以看一下文章里这段代码,我呢引入了一个with name的结构体。
但是呢这样会带来一个问题,就是在初始化的时候啊会变得有点乱。
那么有没有更好的方法呢?那我再来提供另外一个解,在这段代码中啊,我使用了一个叫做stringable的接口。
我用这个接口呢把业务类型、country和city和控制逻辑print给解耦了。
于是呢只要实现了stringable接口,都可以传给print string来使用。
那这种编程模式啊,在构员的标准库里有很多的实例。
那最著名的就是IO点read和IOU til点redow的玩法。
那其中IO点read是是一个接口,你需要实现它的一个read接口方法。
那只要满足这个规则呢,就可以被IOU til点read all这个方法所使用。
那这个呢就是面向对象编程方法的黄金法则,也就是program to the interface, not implementation.另外呢我们可以看到构元的边器呢并没有严格检查一个对象是否实现了某一个接口所有的接构方法。
那这么说呢可能不太好理解,我在文章里啊给你放了一个示例。
在这个例子中啊,square并没有实现shape接口所有的方法啊,虽然程序可以跑通,但这样的编程方式呢并不严谨。
那如果我们需要强制实现结果的所有方法,那应该怎么办呢?在构元的变声圈里啊,有一个比较标准的做法,就是我声明一个下划线的变量,把一个new空指针从square转成ship.那这样如果没有实现完相关的接口方法呢,编器就会报错。
那这样呢就做到了强验证的方法。
接下来呢再聊一聊垢里面的时间。
对于时间来说,这应该是编程中比较复杂的问题了。
相信我时间啊是一种非常复杂的事儿,而且呢时间有时区格式精度等问题。
它的复杂度啊不是一般人能处理的,所以呢一定要乘用已有的时间处理,而不是自己干。
在构元中啊,你一定要使用time点time和time点duration这两个类型。
在命令行程序中呢,flag库通过time点pass duration支持了time duration.而jason中的encoding jason库啊,也可以把time点time编码成RFC三三三九的格式数据库使用的data base circle库啊,也支持把data time或者time steam类型转成time点time.另外呢文件也可以使用ymmyymo v二库,支持time点time、 time点duration和IFC三三三九的格式。
那如果你要和第三方交互,实在没有办法,我也建议你使用RFC三三三九的格式。
最后啊如果你要做全球化跨市区的应用啊,一定要让所有的服务器和时间啊全部使用UTC时间。
那接下来呢我们再来聊一聊性能构元呢是一个高性能的语言,但并不说这样,我们就不用关心性能了啊,我们还是需要关心的那接下来呢我给你提供一份在编程方面和性能相关的提示。
首先,如果你需要把数字转换成字符串使用spring com i to a比format, spring的f函数啊要快一倍左右。
第二,尽可能避免把string转换成字节流,这个转换呢会导致性能的下降。
第三,如果你要在full loop里面对某一个slice使用了pad,那请先把slice的容量扩充到位。
那这样呢可以避免内存重新分配以及系统自动按照二的n次方幂进行扩展,但是呢又用不到的情况,从而避免浪费内存。
第四,使用string buffer或者string builder来拼接字符串。
那这样呢性能会被使用加号或者加等高三到四个数量级。
第五,尽可能使用并发的go routing,然后呢使用sink weight group来同步分片操作。
第六,避免在热代码中啊进行内存分配。
那这样呢会导致GC很忙,尽可能使用sink点儿pool来重用对象。
第七,使用lock free的操作,避免使用mutax,尽可能呢使用think atomic包。
第八,使用IO缓冲IO呢是一个非常非常慢的操作,使用buff IO new write和buff IO new reader可以带来更高的性能。
第九,对于在full loop里面固定的正则表达式呢,一定要使用compile方法编译正则表达式,那这样呢性能会提升两数量级。
第十,如果你需要更高性能的协议呢,需要考虑使用ptotobuff或者message pack,而不是jason.因为jython的序列化和反序列化里面使用了反射。
最后啊你在使用map的时候呢,使用整形的key会比字符串的要快。
因为整形比较呢比字符串比较要快。
那其实呢还有很多不错的技巧,我这里呢给你推荐了一些参考文档,他们可以帮助你写出更好的go的代码。
我把链接呢列在文章里,一定要读一读。
好了,这节课呢就到这里。
那如果你觉得今天的内容对你有所帮助啊,欢迎你帮我分享给更多人。