使用缓存和优先队列解决同步消息乱序的问题

博客介绍了使用缓存和优先队列解决同步消息乱序的问题。在拖拽等触发间隔短、sender路径非线性及网络原因下,消息顺序易错乱。缓存需在receiver端做,基本思想是用一定时延确保消息顺序,将消息加到按发送时间排序的缓存队列中,还提及有优化空间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接: 使用缓存和优先队列解决同步消息乱序的问题

上一篇: cocos 使用帧事件用原生动画包装spine动画

下一篇: cocos 图片放缩变化

小坑, 这个优先队列的toArray不是按照顺序, 应该是最小堆的遍历顺序, 这个应该是出于性能考虑, 所以需要自己转一下, 拿到真正的顺序

http://mauriciosantos.github.io/Buckets-JS/symbols/buckets.PriorityQueue.html

sender 发送同步消息到server

server 接收到sender的消息, 然后将消息发送到receiver

receiver 接受消息执行动作, 实现和sender的同步

问题:

在拖拽等触发间隔很短的情况下, 虽然可以扩大间隔, 使用线性插帧来实现同步, 但是在sender路径是非线性的情况下还是会有一些视觉上的差异

sender发送到server这个中间因为网络原因, server接收的顺序可能不一定准确, 一般server是不会关心这些稍微偏向业务的东西, 只是透传消息... 所以脏活累活都得前端干 o(╥﹏╥)o

server发送给receiver也由于网络原因会导致收到的不一定是发送的顺序, 这也是server做缓存和保证顺序基本上没啥用的原因

所以缓存只能在receiver做

基本思想:

用一定的时延确保消息的顺序

在收到消息后, 等待一段时间, 基本上四倍最小发送间隔就可以了, 一般都是两个消息乱序, 不会太多, 不过这个时间也是可以调节的, 视具体情况而定

在等待的过程中, 如果收到了消息, 将其加到缓存队列中, 队列使用发送时间排序 ,这样每次真正发送的是队列中的最先发送的消息, 而不是最先到达的消息

模拟发送和接受的延迟, 可以看到, 经过网络延时, 收到的未必是按照发送的顺序

up-69ec0a0a9ce244677df635ffbe05e8d7e40.png

延时100ms 使用优先队列做缓存, 可以看到已经是正确的顺序了

up-5fc3f9f6afc340eb5ec80b53db874897cbf.png

应该还有优化空间, 比如可以稀释消息, 或者按照优先级来排序, 鼠标移动优先级应该比点击小

也可以使用rxjs优化代码

import { PriorityQueue } from "buckets-js"
import { sleep } from "../../utils"
export class Receiver {
  constructor() {
    this.dataList = []
    this.isSyncing = false
    this.queue = new PriorityQueue((a, b) => {
      if (a.senderTime < b.senderTime) {
        return 1
      }
      if (a.senderTime > b.senderTime) {
        return -1
      }
      return 0
    })
  }

  onReceive(data) {
    data.receiveTime = +new Date()
    this.dataList.push(data)
    console.log("onReceive", data)
    this.syncData(data)
    // 这个输出的array不是按照顺序的...应该只是最小堆的遍历
    // this.queue.toArray()
  }

  doAction(data) {
    console.log("doAction", data)
  }
  // 收到数据执行同步
  async syncData(data) {
    this.queue.add(data)
    if (!this.isSyncing) {
      this.isSyncing = true
      // 如果没有正在同步, 则开始同步
      // 先等待100ms
      await sleep(100)
      // 队列只要不是空, 就一直执行
      while (!this.queue.isEmpty()) {
        await sleep(32)
        const item = this.queue.dequeue()
        this.doAction(item)
      }
      this.isSyncing = false
    } else {
      // 如果正在同步只加入队列
    }
  }
  toArray() {
    while (!this.queue.isEmpty()) {
      const item = this.queue.dequeue()
      console.log(item)
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值