server接收dtu透传代码_Gopher2020大会干货总结:代码技巧篇
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
而言,必要参数为Addr
和Port
,其他均为可选参数,为此需要为众多可选参数写出各种可能组合的接口,代码冗余会相当严重,一旦后期扩展更多的可选参数,那么接口的数量将会是灾难,同时也无法明确区分哪些是可选参数,在使用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) {}
简化之后接收数量骤减为一个,同时明确了只有Addr
和Port
是必要参数,其他均为可选参数。“代码即文档”这句话在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
字符串的拼接与内存块直接写入的性能区别相差非常大,但凡涉及到字符串的拼接,请使用StringBuilder
或StringBuffer
。
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大会干货总结:代码技巧篇相关推荐
- server接收dtu透传代码_ESP8266 STM32 HTTP json透传实验
关于如何建立一个HTTP的虚拟测试桩的方法如下,通过SoapUI建立一个HTTP测试桩,用来模拟远端HTTP服务器. https://blog.csdn.net/russ44/article/deta ...
- server接收dtu透传代码_Swoole学习笔记二:初探server与client(Client同步)
1.搭建server.php代码 <?php //创建Server对象,监听 127.0.0.1:9501端口 $serv = new swoole_server("127.0.0.1 ...
- 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 ...
- 4g dtu透传模块
4g dtu透传模块,是一款支持双向透明传输的产品,用户使用无需关心复杂的协议,产品为双向透传,只需要简单配置即可.同时产品为4G全网通,支持国内全部运营商网络,通讯模组采用CTA1系列模组,高性价比 ...
- PS如何生成svg代码格式的path路径 - PS技巧篇
PS如何生成svg代码格式的path路径 - PS技巧篇 原文标题:PS中的svg工具是怎么使用的 点击查看:百度教程 技巧,切图出来的小图片,可以通过ps打开,右键生成SVG格式的代码. 以上就是关 ...
- 移动联通电信DTU 透传DTU 无线远距离传输
计讯物联透传DTU,移动.联通.电信5G/4G网络,满足偏远地区无线远距离数据传输需求,广泛应用于工业.农业.环保.水利.气象等行业,实现数据采集上报远程控制中心. 4G DTU TD210 1.标准 ...
- 工程小白问题:数采网关、智慧网关、物联网关、工业网关、DTU透传网关、边缘网关、协议网关、通讯管理机、中控网关、LORA网关、PROFIBUS网关、HART网关,都啥区别?如何判断是否符合工程要求?
什么是数采网关,LoRa数采网关\NB-IOT数采网关\HART数采网关profibus DB 数采网关 数采网关就是数据采集网关,一端对接各种数据采集终端.电子仪器仪表,一般都是工业现场总线通讯传输 ...
- 4G DTU 透传模块简单使用方法
不是打广告,纯记录用途. 最近由于项目需要,买了一批4g 透传模块.众所周知,两个4g模块一般不能直连,需要中间通过搭建服务器来搭桥.卖家把桥搭好了,自己简单配置下,就可以实现模块的 ...
- java发送透传个推_个推——移动推送——消息透传
个推是一个国内的手机消息推送的第三方服务,和"极光(JPush)"是同一类服务. 可以快速的推送一些透传消息和顶栏消息链接消息什么的. 虽然官网有大量的案例和Demo,但是我这里还 ...
最新文章
- 终于把微软BING搜索-SPTAG算法的原理搞清了
- eclipse卸载插件小记
- MyEclipse2015Stable2.0安装破解
- 戴琼海:人工智能的几点思考
- python字符串的内部函数_Python中字符串中内置函数
- python历史5分钟数据_python每5分钟从kafka中提取数据的例子
- [转]supervisor 安装、配置、常用命令
- Cannot detect Web Project version. Please specify version of Web Project through Maven project ...报错
- 语义分割空间上下文关系_多尺度空间注意的语义分割
- Android ExoPlayer播放音视频的使用指南
- 怎么把图片压缩到30K以下?如何用手机快速压缩图片?
- springboot引入validation
- Mac系统go版本升级
- 量子精密测量技术大突破,应用正当时,国仪量子成果斐然
- [ 人力资源面试篇 ] 应届生 “ HR 面 “ 面试分析
- Libgdx Box2D实战---放开那小球(二:Box2D介绍)
- flutter 如何实现上下标效果
- python 发布文章,使用Python自动化发布文章:(一)
- 驱动方腔流SIMPLE方法
- 计算机与农业机械化,计算机与农业机械化的相关性研究.pdf