加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

一些Golang小技巧

发布时间:2020-12-16 18:21:26 所属栏目:大数据 来源:网络整理
导读:今天给大家介绍3个我觉得比较有启发的 Golang 小技巧,分别是以下几个代码片段 nsq里的select写文件和socket io模块里的sendfile fasthttp里对header的处理 nsq里的select读 在nsq中,需要读取之前磁盘上的,或者是从内存中直接读取,一般人都是先判断内存中

今天给大家介绍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   <-----------------------------------------------------+
                         +----------------
  1. http模块对于文件只是简单地直接打开,获取文件描述符(file descriptor)
  2. 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)
      		}
  3. 完成判断,并直接调用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》

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读