以未知的顺序执行函数的最有效方法

Most effective method of executing functions an in unknown order

本文关键字:有效 函数 方法 执行 未知 顺序      更新时间:2023-10-16

假设我有一个很大的,在50到200之间的单个函数池,它们的工作是对单个对象进行操作并修改它。函数池被选择性地放入单个数组中,并按任意顺序排列。

函数本身不接受它正在修改的对象内存在的值以外的参数,这样,对象的行为仅由哪些函数以何种顺序执行决定。

到目前为止,我暂时使用的一种方法是这样的,它可以更好地解释我的目标是什么:
class Behavior{
    public:
    virtual void act(Object * obj) = 0;
};
class SpecificBehavior : public Behavior{
    // many classes like this exist
    public:
    void act(Object * obj){ /* do something specific with obj*/ };
};
class Object{
    public:
    std::list<Behavior*> behavior;
    void behave(){
        std::list<Behavior*>::iterator iter = behavior.front();
        while(iter != behavior.end()){
             iter->act(this);
             ++iter;
        };
    };
};

我的问题是,从性能和可维护性方面考虑,c++中组织这样一个函数池的最有效的方法是什么?这是我正在做的一些人工智能研究,这种方法与我试图实现的目标最接近。

edits:数组本身可以在任何时候被此处未列出的代码的任何其他部分更改,但它保证在调用behave()期间永远不会更改。存储它的数组需要能够更改和扩展到任意大小

如果行为函数没有状态,只接受一个Object参数,那么我会使用函数对象的容器:

#include <functional>
#include <vector>
typedef std::function<void(Object &)> BehaveFun;
typedef std::vector<BehaveFun> BehaviourCollection;
class Object {
  BehaviourCollection b;
  void behave() {
    for (auto it = b.cbegin(); it != b.cend(); ++it) *it(*this);
  }
};

现在只需将所有函数加载到集合中。

如果你将对这个集合做的主要事情是对它进行迭代,你可能会想要使用vector作为解引用和递增你的迭代器将等同于简单的指针算术。

如果你想使用所有的内核,而你的操作不共享任何状态,你可能想看看像Intel的TBB这样的库(参见parallel_for example)

我会保持原样。性能应该是OK的(可能会有额外的间接由于虚表查找,但这应该无关紧要)

我保持原样的原因是:

  1. 你可以将公共子行为提升到behavior和你的实现类之间的中间类。使用函数指针就不那么容易了。

    struct AlsoWaveArmsBase : public Behaviour 
    {
       void act( Object * obj )
       {
          start_waving_arms(obj); // Concrete call
          do_other_action(obj);   // Abstract call
          end_waving_arms(obj);   // Concrete call
       }
       void start_waving_arms(Object*obj);
       void end_waving_arms(Object*obj);
       virtual void do_other_actions(Object * obj)=0;
    };
    struct WaveAndWalk : public AlsoWaveArmsBase
    {
       void do_other_actions(Object * obj) { walk(obj); }
    };
    struct WaveAndDance : pubic AlsoWaveArmsBase
    {
       void do_other_actions(Object * obj) { walk(obj); }    
    }
    
  2. 你可能想在你的行为中使用状态

    struct Count : public Behavior
    {
       Behaviour() : i(0) {}
       int i;
       void act(Object * obj)
       {
          count(obj,i);
          ++i;
       }
    }
    
  3. 您可能想要添加辅助功能,例如,您可能想要添加can_act这样:

    void Object::behave(){
      std::list<Behavior*>::iterator iter = behavior.front();
      while(iter != behavior.end()){
         if( iter->can_act(this) ){
            iter->act(this);
         }
         ++iter;
       };
     };
    

在我看来,这些灵活性超过了转向纯函数方法的好处。

对于可维护性,您当前的方法是最好的(虚函数)。您可能从使用自由函数指针中获得一点好处,但我怀疑它是可测量的,即使是这样,我也不认为值得这么麻烦。当前的OO方法足够快且可维护。我正在谈论的小收益来自于这样一个事实,即您对指向对象的指针解引用,然后(在幕后)对指向函数的指针解引用(这发生在调用虚函数的实现中)。

我不会使用std::function,因为它不是很高性能(尽管在不同的实现中可能会有所不同)。看这个和这个。当你在运行时需要这种动态时,函数指针是最快的。

如果你需要提高性能,我建议你去改进算法,而不是这个实现。