You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Queue计算9个浮点值平均值时偶发InvalidOperationException异常

解决Queue计算平均值时偶尔触发的InvalidOperationException问题

嘿,这个异常我之前做游戏开发处理玩家运动数据时也碰到过!咱们先把问题拆明白:你看到的InvalidOperationException来自Linq的Average()方法,核心原因要么是计算平均值的时候Queue是空的,要么是多线程下Queue被并发修改导致枚举出问题了。

可能的原因和对应的解决办法

1. 空队列直接调用了Average()

Linq的Average()方法如果拿到空序列,直接就会报错——毕竟没法计算0个元素的平均值嘛。如果你的Queue偶尔会被清空(比如玩家状态重置的时候),刚好这时候触发平均值计算,就会出这个问题。

修复方案:
计算前先判断队列里有没有元素,给个默认值兜底:

float avgVelocity = myQueue.Any() ? myQueue.Average() : 0f; // 0f可以换成你需要的默认值,比如前一次的平均值

2. 多线程并发访问Queue引发的问题

Queue<T>本身不是线程安全的!如果你的OnPersonUpdated事件可能在多个线程触发(比如Unity里的网络回调、异步事件),同时另一个线程在计算平均值,那枚举Queue元素的过程中,Queue被其他线程修改(比如入队、出队),就会直接抛出这个异常。

两种靠谱的解决思路:

  • 换用线程安全的ConcurrentQueue<T>:这玩意儿是专门给多线程场景设计的,枚举和增删操作都做了同步,不会因为并发修改出错。用法和普通Queue差不多,只是部分方法名有变化(比如取元素用TryDequeue)。
  • 给普通Queue加锁:用一个锁对象把所有对Queue的读写操作都包起来,确保同一时间只有一个线程能操作它:
// 先定义一个锁对象,要和Queue一起初始化
private readonly object _queueLock = new object();
private Queue<float> _velocityQueue = new Queue<float>(9); // 初始化容量设为9更高效

// 在OnPersonUpdated里入队的时候加锁
private bool OnPersonUpdated(IEvent evt)
{
    var castEvent = evt as Event_Update;
    if (castEvent == null || !peopleDict.ContainsKey(castEvent.id))
        return false;

    float xVel = castEvent.xVel; // 假设你这里拿到了速度值
    lock(_queueLock)
    {
        _velocityQueue.Enqueue(xVel);
        // 保持队列最多9个元素
        if(_velocityQueue.Count > 9)
            _velocityQueue.Dequeue();
    }
    // 其他逻辑...
    return true;
}

// 计算平均值的时候也加锁
private float GetAverageVelocity()
{
    lock(_queueLock)
    {
        return _velocityQueue.Any() ? _velocityQueue.Average() : 0f;
    }
}

结合你的代码场景分析

从你给出的OnPersonUpdated代码片段来看,你应该是在事件回调里往Queue塞速度数据。如果这个事件是异步触发的(比如网络同步过来的玩家数据),那多线程并发访问的概率极高,优先用ConcurrentQueue或者加锁的方式解决,基本就能搞定这个偶尔出现的异常了。


内容的提问来源于stack exchange,提问作者Bachalo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:05:13