C++ 需要加速C++;代码涉及Boost多索引和对无序\u多映射的查找

C++ 需要加速C++;代码涉及Boost多索引和对无序\u多映射的查找,c++,boost,multimap,multi-index,unordered,C++,Boost,Multimap,Multi Index,Unordered,我正在寻找加速基于代理的模型的策略,该模型基于类Host的对象,指向这些对象的指针存储在Boost多索引容器中。我使用Shark确定绝大多数时间都被函数calcSI()消耗: 函数calcSI()必须为类Host的每个实例计算某些概率,这些概率取决于类Host的其他实例的属性。(大约有10000-50000个主机的实例,每个主机大约运行25600次这些计算。) 如果我正确地解释了配置文件,那么花在calcSI()上的大部分时间都花在了Host::isInfectedZ(int),它只计算类型为

我正在寻找加速基于代理的模型的策略,该模型基于类
Host
的对象,指向这些对象的指针存储在Boost多索引容器中。我使用Shark确定绝大多数时间都被函数
calcSI()
消耗:

函数
calcSI()
必须为类
Host
的每个实例计算某些概率,这些概率取决于类
Host
的其他实例的属性。(大约有10000-50000个
主机的实例
,每个主机大约运行25600次这些计算。)

如果我正确地解释了配置文件,那么花在
calcSI()
上的大部分时间都花在了
Host::isInfectedZ(int)
,它只计算类型为
InfectionMap
的Boost无序多映射中的某些实例:

  • 我很难找到有关Boost无序多重映射的
    count
    函数成本的信息。我是否应该通过向
    Host
    添加一个单独的二维数组来跟踪每个键的实例数(即与每个
    int
    关联的
    感染数)来增加开销

  • 我想知道,对Boost多重指数进行更大规模的结构性改革,比如取消一两个不太需要的综合关键指数,是否会更有帮助。多索引的后台维护没有出现在探查器中,这(可能是愚蠢的)让我担心它可能会很大。我在多索引中有8个索引,其中大多数是有序的非唯一的

  • 是否有其他我应该关注的事情可能不会出现在探查器中,或者我错过了探查器的主要结果

  • 不幸的是,
    calcSI()
    的并行化和多线程不是选项

    更新:知道
    InfectionMap车厢
    很少有超过10对并且通常有可能会有帮助,就像您在#1中建议的那样,尝试在Host::Carries unordered_multimap旁边维护一个车厢计数数组,并保持两者“同步”。然后,您的Host::isInfectedZ将使用(希望)更快的回车计数数组:

    int Host::isInfectedZ( int z ) const {
      return carriageCount[ z ];
    }
    
    如果可以传递到isInfected的整数范围较大,则使用关联数组进行回车计数

    对于关联数组,可以使用std::map或boost::unordered。对于查找,前者具有对数时间复杂度,后者具有恒定时间复杂度。但由于这个关联数组通常非常小,std::map实际上可能更快。std::map也可能占用更少的空间开销。尝试这两种方法并运行探查器查看。我赌的是std::map.:-)

    编辑:

    在看到您对我的评论的回答后,我建议使用常规的固定大小数组进行运输计数。忘掉关联数组的东西吧

    编辑2:

    你可能想放弃

    typedef boost::unordered_multimap< int, Infection > InfectionMap;
    
    typedef boost::无序的多重映射感染映射;
    
    然后把你自己手写的InfectionMap类卷起来,因为你要处理这么小的索引

    对第二次更新的回应:

    很高兴看到你有所进步。我怀疑你会发现一个容器比一个固定的数组,比如说16个整数“体积更小”。STL和boost容器以块的形式分配内存,即使它们只有很少的元素,最终也会和固定大小的数组一样大


    您可能对boost::array感兴趣,它将类似STL的接口封装在C样式的固定数组中。这将使使用std::vector或std::map“交换”固定大小的数组变得更容易。

    可以传递到Host::isInfected的整数范围是多少?@Emile:范围从0到
    const int INIT\u NUM\u STYPES-1
    。大多数情况下(即,在大多数模拟中)
    INIT_NUM_STYPES=4
    ,但有时我会将其设置为8或10。换句话说,
    Host::isInfectedZ(int z)
    通常具有
    z
    =0、1、2或3。这是使用预先退出的容器和算法简化生活和代码易读的完美示例。它告诉你什么时候你需要开始使用指针和c风格的数组来接近裸机。谢谢,在你写这个答案的时候,我正在做我的更新#2。普通的旧阵列目前运行良好,但我非常感谢您为具有更大范围的
    z
    的情况提供建议。当我开始用
    std::map
    测试更大的范围时,我会更新这篇文章(可能在几天到一周内)。谢谢。我不会太担心的,除非你遇到了内存问题。为了额外的速度而牺牲内存是完全正常的——正如您的基准测试所证明的那样,您的案例证明了这一点。
    int Host::isInfectedZ( int z ) const {
      //return carriage.count( z );
      return carriageSummary[ z ];
    }
    
    int Host::isInfectedZ( int z ) const {
      return carriageCount[ z ];
    }
    
    typedef boost::unordered_multimap< int, Infection > InfectionMap;