一些Golang小技巧
今天给大家介绍3个我觉得比较有启发的Golang小技巧,分别是以下几个代码片段
- nsq里的select写文件和socket
- io模块里的sendfile
- fasthttp里对header的处理
nsq里的select读
在nsq中,需要读取之前磁盘上的,或者是从内存中直接读取,一般人都是先判断内存中有没有数据,然而,nsq另辟蹊径使用了select语句,把CSP模式用到了极致。
源文件链接:channel.go
select {
case msg = <-c.memoryMsgChan: //尝试从内存中读取
case buf = <-c.backend.ReadChan(): //如果内存中没有,直接从磁盘上读取
msg, err = decodeMessage(buf)
if err != nil {
c.ctx.nsqd.logf("ERROR: failed to decode message - %s", err)
continue
}
io模块中的sendfile
经过精巧的io.ReadFrom interface设计,sendfile对上层的http handler完全透明,具体调用如图所示
+----------------+
| http.ServeFile |
+--------+-------+
|
+--------+--------+ +----------------+ +---------------------------------+
| os.File +------> io.Copy | | http.Response |
+--------+--------+ +--------+-------+ | +-----------------------------+ |
| | | | net.TCPConn | |
| +--------v-------+ 2. has? | | +-------------------------+ | |
| | io.CopyBuffer +---------> | | | io.ReadFrom | | +-----+
| +--------+-------+ | | | +---------------------+ | | | |
| | | | | | sednfile (syscall) | | | | |
| | | | | +---------------------+ | | | |
| | | | +-------------------------+ | | |
| | | +-----------------------------+ | |
| | +---------------------------------+ |
| 4. do it! +--------v------+ 3. YES! |
+---------------> syscall <-----------------------------------------------------+
+----------------
- http模块对于文件只是简单地直接打开,获取文件描述符(file descriptor)
- http模块调用io.Copy函数,io.Copy函数开始检查Reader Writer是否特殊的ReadFrom,WriteTo接口 func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { // bla.... // Similarly, if the writer has a ReadFrom method, use it to do the copy. if rt, ok := dst.(ReaderFrom); ok { return rt.ReadFrom(src) }
- 完成判断,并直接调用net.TCPConn模块下的ReadFrom接口,里面写上了sendfile func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) { if n, err, handled := sendFile(c.fd, r); handled { if err != nil && err != io.EOF { err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} } return n, err } // skipped....
这样io.Copy的使用者其实不知道自己默默地用了sendfile,同时又保持了接口一致性和很低的耦合度。
更深入的可以移步谢大的教程- interface
fasthttp对于header的处理
fasthttp为什么会比net.http快,其中一个原因就是fasthttp并没有完全地解析所有的http请求header数据。这种做法也称作lazy loading。首先我们从header的struct开始看起吧。
type RequestHeader struct {
//bla.....
contentLength int
contentLengthBytes []byte
method []byte
requestURI []byte
host []byte
contentType []byte
userAgent []byte
h []argsKV
bufKV argsKV
cookies []argsKV
rawHeaders []byte
}
可能大家都很奇怪,Request里没有string,明明method、host都可以用string啊,这是由于string是不可变类型,而从Reader中读出的[]byte是可变类型,因此,从[]byte转化为string时是有copy和alloc行为的。虽然数据量小时,没有什么影响,但是构建高并发系统时,这些小的数据就会变大变多,让gc不堪重负。
request中还有一个特殊的argsKV
type argsKV struct {
key []byte
value []byte
}
其实和上面的理由是一样的,net.http中使用了map[string]string来存储各种其他参数,这就需要alloc,为了达成zero alloc,fasthttp采用了遍历所有header参数来返回,其实也有一定的考虑,那就是大部分的header数量其实都不多,而每次对于短key对比只需要若干个CPU周期,因此算是合理的tradeoff(详见bytes.Equal汇编实现 )
对于[]byte alloc的优化,可以参考Dave Cheney的《Five things that make go fast》
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- laravel利用中间件做防非法登录和权限控制示例
- laravel框架中表单请求类型和CSRF防护实例分析
- Yii框架getter与setter方法功能与用法分析
- laravel框架中视图的基本使用方法分析
- laravel5 Eloquent 实现事务方式
- Laravel 微信小程序后端搭建步骤详解
- Laravel使用swoole实现websocket主动消息推送的方法介绍
- Laravel框架Eloquent ORM删除数据操作示例
- PHP常用函数之base64图片上传功能详解
- laravel-admin 实现在指定的相册下添加照片
- Laravel框架Eloquent ORM修改数据操作示例
- PHP常用函数之格式化时间操作示例
- 在phpstudy集成环境下的nginx服务器下配置url重写
- 关于laravel-admin ueditor 集成并解决刷新的问题
- PHP常用函数之根据生日计算年龄功能示例