加入收藏 | 设为首页 | 会员中心 | 我要投稿 安阳站长网 (https://www.0372zz.cn/)- 高性能计算、分布式云、混合云存储、云计算、视频终端!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

优雅的读取http请求或响应的数据

发布时间:2019-01-31 15:10:28 所属栏目:教程 来源:戚银
导读:从 http.Request.Body 或 http.Response.Body 中读取数据方法或许很多,标准库中大多数使用 ioutil.ReadAll 方法一次读取所有数据,如果是 json 格式的数据还可以使用 json.NewDecoder 从 io.Reader 创建一个解析器,假使使用 pprof 来分析程序总是会发现

以上是标准库 ioutil.ReadAll 的代码,每次会创建一个 var buf bytes.Buffer 并且初始化 buf.Grow(int(capacity)) 的大小为 bytes.MinRead, 这个值呢就是 512,按这个 buffer 的大小读取一次数据需要分配 2~16 次内存,天啊简直不能忍,我自己创建一个 buffer 好不好。

看一下火焰图🔥吧,其中红框标记的就是 ioutil.ReadAll 的部分,颜色比较鲜艳。

优雅的读取http请求或响应的数据

优化读取方法

自己创建足够大的 buffer 减少因为容量不够导致的多次扩容问题。

  1. buffer := bytes.NewBuffer(make([]byte, 4096)) 
  2. _, err := io.Copy(buffer, request.Body) 
  3. if err !=nil{ 
  4.     return nil, err 
  5. } 

恩恩这样应该差不多了,为啥是初始化 4096 的大小,这是个均值,即使比 4096 大基本也就多分配一次内存即可,而且大多数数据都是比 4096 小的。

但是这样真的就算好了吗,当然不能这样,这个 buffer 个每请求都要创建一次,是不是应该考虑一下复用呢,使用 sync.Pool 建立一个缓冲池效果就更好了。

以下是优化读取请求的简化代码:

  1. package adapter 
  2.  
  3. import ( 
  4.     "bytes" 
  5.     "io" 
  6.     "net/http" 
  7.     "sync" 
  8.  
  9.     "github.com/json-iterator/go" 
  10.     "github.com/sirupsen/logrus" 
  11.     "github.com/thinkeridea/go-extend/exbytes" 
  12. ) 
  13.  
  14. type Adapter struct { 
  15.     pool sync.Pool 
  16. } 
  17.  
  18. func New() *Adapter { 
  19.     return &Adapter{ 
  20.         pool: sync.Pool{ 
  21.             New: func() interface{} { 
  22.                 return bytes.NewBuffer(make([]byte, 4096)) 
  23.             }, 
  24.         }, 
  25.     } 
  26. } 
  27.  
  28. func (api *Adapter) GetRequest(r *http.Request) (*Request, error) { 
  29.     buffer := api.pool.Get().(*bytes.Buffer) 
  30.     buffer.Reset() 
  31.     defer func() { 
  32.         if buffer != nil { 
  33.             api.pool.Put(buffer) 
  34.             buffer = nil 
  35.         } 
  36.     }() 
  37.  
  38.     _, err := io.Copy(buffer, r.Body) 
  39.     if err != nil { 
  40.         return nil, err 
  41.     } 
  42.  
  43.     request := &Request{} 
  44.     if err = jsoniter.Unmarshal(buffer.Bytes(), request); err != nil { 
  45.         logrus.WithFields(logrus.Fields{ 
  46.             "json": exbytes.ToString(buffer.Bytes()), 
  47.         }).Errorf("jsoniter.UnmarshalJSON fail. error:%v", err) 
  48.         return nil, err 
  49.     } 
  50.     api.pool.Put(buffer) 
  51.     buffer = nil 
  52.  
  53.     // .... 
  54.      
  55.     return request, nil 
  56. } 

(编辑:安阳站长网)

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

热点阅读