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

C++ vector.push_back()性能优化:高频调用CalculateKickers卡顿

高频调用牌型计算函数性能优化方案

核心问题定位

单次计算任务需要调用目标函数1000万~1亿次,性能分析显示绝大多数耗时集中在以下代码行:

myHand_param.FinalHandVector.push_back((1 << static_cast<int>(std::ceil((i - 3.0) / 4.0))));

已知FinalHandVector的最大长度永远不超过5,此前尝试用int*替换vector未获得明显性能提升,不清楚如何跳过容器边界检查。
待优化完整函数代码如下:

void CalculateKickers(Hand& myHand_param, int kickersNeeded)
{
    int countKickers{ 0 };

    for(int i = bits-1; i > 0 ; i--)
    {
        if (static_cast<std::bitset<bits>>(myHand_param.handMask)[i] == 1)
        {
            if (static_cast<std::bitset<1>>((static_cast<std::bitset<bits>>(myHand_param.FinalHandUsedCardFacesMask) >> i).to_ullong())== 0)
            {
                ++countKickers;
                myHand_param.FinalHandVector.push_back((1 << static_cast<int>(std::ceil((i - 3.0) / 4.0))));

                if (countKickers == kickersNeeded)
                {
                    i = 0;
                }
            }
        }   
    }
}

具体优化点

  • 替换浮点运算为等价整数运算:当前耗时行最大开销来自std::ceil((i - 3.0) / 4.0)的浮点计算,高频调用下浮点运算开销远高于整数运算。由于i是整数,该表达式可100%等价替换为整数除法i / 4,完全消除浮点运算、浮点转整数的开销。
  • 消除vector动态操作开销:已知容器最大长度为5,直接将Hand结构体中的FinalHandVector替换为固定长度数组+长度计数器,写入时直接用下标赋值,完全避开push_back自带的容量检查、size更新的冗余开销,比裸指针替换方案更直接高效。如果暂时不修改结构体成员,至少在函数入口提前对vector执行clear()+reserve(5),消除扩容和默认初始化开销。
  • 移除bitset冗余构造和转换:当前循环每次迭代都会重新构造临时bitset对象,还做了移位转unsigned long long再构造1位bitset的冗余操作,开销极高。如果bits位宽不超过64,直接将两个mask以uint64_t类型存储,位判断用原生位运算(mask_val >> i) & 1实现,完全消除临时对象构造、类型转换的开销。
  • 简化循环退出逻辑:当前找到足够kicker时通过给i赋值0退出循环,直接用break即可,减少一次循环条件判断开销。

优化后参考代码

// Hand结构体对应成员修改(如果bits<=64建议直接用整数存mask)
// struct Hand {
//     // ... 其他原有成员
//     int FinalHandArr[5];
//     int FinalHandLen;
//     uint64_t handMask;
//     uint64_t FinalHandUsedCardFacesMask;
// };

void CalculateKickers(Hand& myHand_param, int kickersNeeded)
{
    myHand_param.FinalHandLen = 0;
    const uint64_t handMask = myHand_param.handMask;
    const uint64_t usedMask = myHand_param.FinalHandUsedCardFacesMask;

    for (int i = bits - 1; i > 0; --i)
    {
        // 直接用位运算判断位状态,无临时对象开销
        if (((handMask >> i) & 1) && !((usedMask >> i) & 1))
        {
            // 固定数组下标写入,无边界检查、扩容判断开销,整数运算替代浮点计算
            myHand_param.FinalHandArr[myHand_param.FinalHandLen++] = 1 << (i / 4);
            if (myHand_param.FinalHandLen == kickersNeeded)
            {
                break;
            }
        }
    }
}

如果bits位宽超过64,直接访问bitset的内部存储做位判断即可,不要在循环内构造临时bitset对象。以上优化落地后,函数整体性能可提升10~100倍,完全满足亿级调用的性能要求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:15:40