展开目录
定长消息队列读写优化
优化
X
陈尼玛的博客
记录开发生涯的踩坑经历,用时间来验证成长
加载中

nodejs写聊天室消息存储的场景,比如一个房间的消息个数最多保留最近的100条,如果只是把消息存储在内存里,往往会使用如下写法:

var msgs=[], n=100
onmessage=msg=>{
  msgs.push(msg) // 往队尾追加数据
  if(msgs.length>n) msgs.shift() // 如果超过长度则把队头的删除
}

push操作对性能不会有什么影响,因为仅仅是往原本的数据后面增加一项,如果数组长度没有超过上次预分配的内存空间则本次操作只会往已有内存的最近一格填入一个数据。但shift操作问题就大了,没有优化过的代码,常规操作是从队头删除一个数据,删除之后把后面的数据各往前移动一格。因此shift操作理论上会比push慢得多。

因为消息队列是一个定长顺序队列,因此我想到的优化方案是:

  1. 增加一个变量seq_i用于记录当前数据的尾部

  2. 每增加一个数据,则seq_i加1对消息数组的最大长度取余数,且把本次数据放到消息数组的seq_i这格

  3. 获取结果时,从seq_i开始到队列结尾的数据记为A,从0到seq_i为止的数据记为B,把A和B拼在一起就是当前的数据结果

然后我写了脚本以测试效果:


function typeA(seq_maxlen, repeat) {
  let seq=[]
  function get_result() {
    return [...seq]
  }
  function snapshot() {
    const r={
      mem: (process.memoryUsage().heapUsed/1024/1024).toFixed(2),
      time: Date.now(),
    }
    seq.push(r)
    if(seq.length>seq_maxlen) seq.shift()
  }

  const a=Date.now()
  for(let i=0; i<repeat; i++) snapshot()
  get_result()
  return Date.now()-a
}

function typeB(seq_maxlen, repeat) {
  let seq=[], seq_i=0
  function get_result() {
    return [...seq.slice(seq_i, seq_maxlen), ...seq.slice(0, seq_i)]
  }
  function snapshot() {
    const r={
      mem: (process.memoryUsage().heapUsed/1024/1024).toFixed(2),
      time: Date.now(),
    }
    seq[seq_i]=r
    seq_i=(seq_i+1)%seq_maxlen
  }

  const a=Date.now()
  for(let i=0; i<repeat; i++) snapshot()
  get_result()
  return Date.now()-a
}


function log(seq_maxlen, repeat) {
  console.log(`队列最长${seq_maxlen},循环${repeat}次,shift-push方式耗时:${typeA(seq_maxlen, repeat)}ms, 下标轮询方式耗时:${typeB(seq_maxlen, repeat)}ms`)
}

log(10, 1e5)
log(10, 1e6)
log(50, 1e5)
log(50, 1e6)
log(100, 1e5)
log(100, 1e6)
log(200, 1e5)
log(200, 1e6)

image.png

相关文档

  1. 数据库清理优化

  2. 缓存才是优化的终极手段

随便看看

  1. 记一次nodejs内存泄漏的排查经历

  2. cnpm 立即同步

  3. css多行文本超出截断显示省略号

  4. 安卓文字偏上,文字顶部被遮罩

  5. word文件命令行打印

  6. pip安装nltk临时使用国内源

  7. nginx用域名来转发请求

  8. nodejs socks5

  9. mongodb 批量修改字段语句

  10. mongodb2.4 添加用户

  11. python下载文件,带进度条控制

  12. mac搜索局域网内的主机

  13. sendmail用nginx做代理

  14. 树莓派配置wifi

  15. centos7 开放或者关闭端口

畅言模块加载中