Gopher2020大会已经结束了几天,圈内大牛的分享可谓干货满满,分享内容涉及到诸多的业务、框架、理念等,本文系会后粗略整理,主要是将一些干货内容总结、分类;本文内容不涉及业务、框架以及设计理念,整理重点在于Go的代码技巧;这些技巧并非准则,而是由一个个小tips组成,如有疏漏或错误的地方,烦请看官指正。

Functional Options

这个主题左耳朵耗子(陈皓)和毛剑都有讲到过。毛剑老师对此的总结非常精炼:从代码层面可以明确区分接口的必要参数和可选参数。以陈皓老师的代码为例:

type Server struct {Addr stringPort intProtocol stringTimeout time.DurationMaxConns intTLS *tls.Config
}func NewServer(addr string, port int) (*Server, error) {}
func NewTLSServer(addr string, port int, tls *tls.Config) (*Server, error) {}
func NewServerWithTimeout(addr string, port int, timeout time.Duration) (*Server, error) {}
func NewTLSServerWithMaxAndTimeout(addr string, port int, maxconns int, timeout time.Duration, tls *tls.Config)(*Server, error) {}

对于Server而言,必要参数为AddrPort,其他均为可选参数,为此需要为众多可选参数写出各种可能组合的接口,代码冗余会相当严重,一旦后期扩展更多的可选参数,那么接口的数量将会是灾难,同时也无法明确区分哪些是可选参数,在使用Functional Options后,接口可以简化为一个。

type Option func (*Server)
func Protocol(proto string) Option {return func(s *Server) {s.Protocol = proto}
}func Timeout(timeout time.Duration) Option {return func(s *Server) {s.Timeout = timeout}
}func MaxConns(maxconns int) Option {return func(s *Server) {s.MaxConns = maxconns}
}func TLS(tls *tls.Config) Option {return func(s *Server) {s.TLS = tls}
}func NewServer(addr string, port int, options ...func(*Server)) (*Server, error) {}

简化之后接收数量骤减为一个,同时明确了只有AddrPort是必要参数,其他均为可选参数。“代码即文档”这句话在Functional Options得到最好的体现。

Error Handling

同样也是陈皓老师带来的一种代码简化技巧:

func Parse(reader io.Reader) (*Point, error) {var point Pointif err := binary.Read(reader, binary.BigEndian, &point.Longitude); err != nil {return nil, error}if err := binary.Read(reader, binary.BigEndian, &point.Latitude); err != nil {return nil, error}if err := binary.Read(reader, binary.BigEndian, &point.Distance); err != nil {return nil, error}if err := binary.Read(reader, binary.BigEndian, &point.EleationLoss); err != nil {return nil, error}return &point, nil
}

想必很多同学都有以上代码的经历,error的处理冗长累赘,读写相当累人。以上代码可以优化成:

func Parse(read io.Reader) (*Point, error) {var point Pointvar err errorread := func (data interface{}) {if err != nil {return}err = binary.Read(read, binary.BigEndian, data)}read(&point.Longitude)read(&point.Latitude)read(&point.Distance)read(&point.EleationLoss)if err != nil {return nil ,err}return &point, nil
}

这种错误处理办法我曾在gouxp中也使用过。

Deep Comparison

在各种复杂业务需求里面,总会遇到各式对象之间需要比较是否相等,Go中没有C++的操作符重载,那么如何实现对象之间的比较呢?答案是Deep Comparison,本质是反射对象,逐一比较对象类型的所有字段。

type data struct {num     intchecks  [10]func() booldoit    func() boolm       map[string]stringbytes   []byte
}func main() {v1 := data{}v2 := data{}fmt.Println("v1 == v2:", reflect.DeepEqual(v1, v2))m1 := map[string]string{"one": "a", "two": "b"}m2 := map[string]string{"two": "b", "one": "a"}fmt.Println("m1 == m2:", reflect.DeepEqual(m1, m2))s1 := []int{1, 2, 3}s2 := []int{1, 2, 3}fmt.Println("s1 == s2:", reflect.DeepEqual(s1, s2))
}

当然,使用reflect.DeepEqual也是需要谨慎考虑的,毕竟反射很慢

Interface Partterns

严格来说,这个issue是我根据陈皓老师的内容得出的一点启发,同时也是我在gouxp中的关于接口的小技巧实践。

type Conn interface {}func (conn *Conn) Close(err error) {}

Conn是一个TCP连接的抽象,一条网络连接在Client和Server端都会存在一个Conn对象,如果Client Conn和Server Conn的关闭逻辑有区别,那该如何实现Close函数呢?是独立写ClientClose、ServerClose还是将Conn进一步抽象为两端分别使用的interface?

在C++里面,使用多态重写即可解决,那么在Go中呢?

type ConnCloser interface {close(err error)
}type Conn interface {ConnCloser
}func (conn *Conn) Close(err error) {conn.close(err)
}

客户端和服务端各自实现ConnCloser即可实现逻辑分离。

Avoid string to byte conversion

众所周知,字符串到byte的直接转换是很昂贵的,所以代码中要尽量避免string与byte之间的直接转换。writer.Write(byteData)要明显好于writer.Write([]byte("HelloWorld")),有兴趣的同学可以跑个Benchmark看看效果。

Use StringBuilder and StringBuffer

字符串的拼接与内存块直接写入的性能区别相差非常大,但凡涉及到字符串的拼接,请使用StringBuilderStringBuffer

Avoid Link Node When Use sync.Pool

有这样的代码:

type message struct {childMsg []*message
}var msgPool = sync.Pool{New: func() interface{} {return &message{make([]*message, 0, 8)}
}}func NewMsg(parent *message) *message {ret := msgPool.Get().(*messa(ge)if parent != nil && len(parent.childMsg) < 8 {parent.childMsg = appen(parent.childMsg, ret)}return ret
}func RecycleMessage(msg *message) {msg.childMsg = msg.childMsg[:0]msgPool.Put(msg)
}

从上面可以看出,相当混乱的引用关系导致sync.Pool无法成功回收进而导致内存泄漏,因此在sync.Pool的使用上要注意可能存在父子关系或其他复杂引用关系的对象

Channel Pipeline

假设有这样的需求:对一组数值逐个进行平方运算,然后再逐个求和,该如何实现?仔细分析需求,有两个计算阶段是先平方再求和,那么所需数据如何传递呢?函数参数吗?如何平方或求和相当耗时应该怎么处理呢?

从Go的官方博客上可以找到关于Channel Pipeline的概念:

  • Receive values from upstream via inbound channels
  • Perform some function on that data, usually producing new values
  • Send values downstream via outbound channels

本质上就是阶段和数据的拆分,使用chan作为数据中轴;这样每个阶段有独立的实现逻辑互不影响,各个阶段可以并发实现,输入与输出均为chan,典型的生产者消费者场景。

func echo(nums []int) <-chan int {out := make(chan int)go func() {for _, n := range nums {out <- n}close(out)}()return out
}func sq(in <-chan int) <-chan int {out := make(chan int)go func() {for n := range in {out <- n * n}close(out)}()return out
}func sum(in <-chan int) <-chan int {out := make(chan int)go func() {var sum intfor n := range in {sum += n}out <- sumclose(out)}()return out
}
func main() {var nums = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}for n := range sum(sq(echo(nums))) {fmt.Println(n)}
}

延伸阅读

  • Go Concurrency Patterns: Pipelines and cancellation
  • Effective Go
  • Uber Go Style
  • 50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang Devs
  • Go Advice
  • Practical Go Benchmarks
  • Benchmarks of Go serialization methods
  • Debugging performance issues in Go programs
  • Go code refactoring: the 23x performance hunt
  • Golang Error Handling lesson
  • Errors are values
  • Why Go haven’t Map/Reduce?
  • Advanced Go Concurrency Patterns

server接收dtu透传代码_Gopher2020大会干货总结:代码技巧篇相关推荐

  1. server接收dtu透传代码_ESP8266 STM32 HTTP json透传实验

    关于如何建立一个HTTP的虚拟测试桩的方法如下,通过SoapUI建立一个HTTP测试桩,用来模拟远端HTTP服务器. https://blog.csdn.net/russ44/article/deta ...

  2. server接收dtu透传代码_Swoole学习笔记二:初探server与client(Client同步)

    1.搭建server.php代码 <?php //创建Server对象,监听 127.0.0.1:9501端口 $serv = new swoole_server("127.0.0.1 ...

  3. server接收dtu透传代码_深入ASP.NET Core源代码之 - Web Server Kestrel

    测试代码运行环境: OS:Ubuntu 18.04 64bit .NET Core SDK Version: 3.1.101 源代码版本:release/3.1 Kestrel的本质 - Web Se ...

  4. 4g dtu透传模块

    4g dtu透传模块,是一款支持双向透明传输的产品,用户使用无需关心复杂的协议,产品为双向透传,只需要简单配置即可.同时产品为4G全网通,支持国内全部运营商网络,通讯模组采用CTA1系列模组,高性价比 ...

  5. PS如何生成svg代码格式的path路径 - PS技巧篇

    PS如何生成svg代码格式的path路径 - PS技巧篇 原文标题:PS中的svg工具是怎么使用的 点击查看:百度教程 技巧,切图出来的小图片,可以通过ps打开,右键生成SVG格式的代码. 以上就是关 ...

  6. 移动联通电信DTU 透传DTU 无线远距离传输

    计讯物联透传DTU,移动.联通.电信5G/4G网络,满足偏远地区无线远距离数据传输需求,广泛应用于工业.农业.环保.水利.气象等行业,实现数据采集上报远程控制中心. 4G DTU TD210 1.标准 ...

  7. 工程小白问题:数采网关、智慧网关、物联网关、工业网关、DTU透传网关、边缘网关、协议网关、通讯管理机、中控网关、LORA网关、PROFIBUS网关、HART网关,都啥区别?如何判断是否符合工程要求?

    什么是数采网关,LoRa数采网关\NB-IOT数采网关\HART数采网关profibus DB 数采网关 数采网关就是数据采集网关,一端对接各种数据采集终端.电子仪器仪表,一般都是工业现场总线通讯传输 ...

  8. 4G DTU 透传模块简单使用方法

    不是打广告,纯记录用途.          最近由于项目需要,买了一批4g 透传模块.众所周知,两个4g模块一般不能直连,需要中间通过搭建服务器来搭桥.卖家把桥搭好了,自己简单配置下,就可以实现模块的 ...

  9. java发送透传个推_个推——移动推送——消息透传

    个推是一个国内的手机消息推送的第三方服务,和"极光(JPush)"是同一类服务. 可以快速的推送一些透传消息和顶栏消息链接消息什么的. 虽然官网有大量的案例和Demo,但是我这里还 ...

最新文章

  1. 终于把微软BING搜索-SPTAG算法的原理搞清了
  2. eclipse卸载插件小记
  3. MyEclipse2015Stable2.0安装破解
  4. 戴琼海:人工智能的几点思考
  5. python字符串的内部函数_Python中字符串中内置函数
  6. python历史5分钟数据_python每5分钟从kafka中提取数据的例子
  7. [转]supervisor 安装、配置、常用命令
  8. Cannot detect Web Project version. Please specify version of Web Project through Maven project ...报错
  9. 语义分割空间上下文关系_多尺度空间注意的语义分割
  10. Android ExoPlayer播放音视频的使用指南
  11. 怎么把图片压缩到30K以下?如何用手机快速压缩图片?
  12. springboot引入validation
  13. Mac系统go版本升级
  14. 量子精密测量技术大突破,应用正当时,国仪量子成果斐然
  15. [ 人力资源面试篇 ] 应届生 “ HR 面 “ 面试分析
  16. Libgdx Box2D实战---放开那小球(二:Box2D介绍)
  17. flutter 如何实现上下标效果
  18. python 发布文章,使用Python自动化发布文章:(一)
  19. 驱动方腔流SIMPLE方法
  20. 计算机与农业机械化,计算机与农业机械化的相关性研究.pdf

热门文章

  1. HTML中Css补充资料
  2. 解决ionic 2载入速度慢的问题
  3. 从SharePoint 2013迁移到SharePoint Online - 评估工具
  4. 现代软件工程 第3-6章 作业
  5. Linux 安装 nginx注意
  6. C++ Regsvr32订购具体解释
  7. 读《NoSQL精粹》前三章有感
  8. SQLServer扩展存储过程
  9. linux中OpenVas 漏洞扫描软件
  10. java 匿名类实现6_java匿名内部类,以及实现Comparato和Comparable接口实现对对象的排序...