C ++ Problém s výkonem

hlasů
0

Mám trochu dilema s C ++ kódu. Jeho vlastně problém výkonu. Snažím se přejít přes dva hash_maps, který je příčinou hodně pomalu. Heres mapě hash kódu třídy. Dejte mi vědět, jestli jsem něco chybí z tohoto.

  template<class Handle, class Object, class HashFunc, vector<Object *> (*initFunc)()>
  class ObjMapping: public BaseCache
  {

  public:
    typedef ObjMapping<Handle, Object, HashFunc, initFunc> ObjMappingType;
    typedef InvalidObjectException<Handle> InvalidHandle;
    typedef typename ReferenceCounted<Object>::ObjRef ObjRef;

  protected:
    typedef dense_hash_map<Handle, pair<int, ObjRef> , HashFunc> ObjHashMap;
    typedef typename dense_hash_map<Handle, pair<int, ObjRef> , HashFunc>::iterator ObjHashMapIterator;
    typedef typename dense_hash_map<Handle, pair<int, ObjRef> , HashFunc>::const_iterator ObjHashMapConstIterator;

  public:

    class iterator
    {

    public:
      typedef Object &reference;
      typedef ObjRef pointer;

      iterator(ObjMappingType &container, ObjHashMapIterator start) :
        base(start), container_(&container)
      {
        incIterCount_();
      }

      iterator(const iterator &rhs) :
        base(rhs.base), container_(rhs.container_)
      {
        Monitor crit(container_->getIterMutex());
        incIterCount_();
      }

      void operator =(const iterator &rhs)
      {
        if (this != &rhs)
        {
          Monitor crit(container_->getIterMutex());
          decIterCount_();
          base = rhs.base;
          container_ = rhs.container_;
          incIterCount_();
        }
      }

      ~iterator()
      {
        Monitor crit(container_->getIterMutex());
        decIterCount_();
      }

      reference operator *() const
      {
        return *base->second.second;
      }
      pointer operator ->() const
      {
        return base->second.second;
      }

      iterator operator ++()
      {
        {
          Monitor crit(container_->getIterMutex());
          decIterCount_();
          ++base;
          incIterCount_();
        }
        return *this;
      }
      iterator operator ++(int)
      {
        iterator result = *this;
        {
          Monitor crit(container_->getIterMutex());
          decIterCount_();
          ++base;
          incIterCount_();
        }
        return result;
      }
      iterator operator --()
      {
        {
          Monitor crit(container_->getIterMutex());
          decIterCount_();
          --base;
          incIterCount_();
        }
        return *this;
      }
      iterator operator --(int)
      {
        iterator result = *this;
        {
          Monitor crit(container_->getIterMutex());
          decIterCount_();
          --base;
          incIterCount_();
        }
        return result;
      }

      bool operator ==(const iterator &i) const
      {
        return (base == i.base);
      }
      bool operator !=(const iterator &i) const
      {
        //return !(*this == i);
        return (base != i.base);
      }

    private:
      void incIterCount_()
      {
        if (!container_->endIterator(base))
        {
          ++base->second.first;
        }
      }
      void decIterCount_()
      {
        if (!container_->endIterator(base) && --base->second.first == 0)
        {
          container_->wake();
        }
      }

      ObjHashMapIterator base;
      ObjMappingType *container_;
    };

    ~ObjMapping()
    {
    }

    bool validObj(const Handle &id) const
    {
      Monitor crit(mutex);
      MethodTracker track (ObjMapping::validObj);
      return objs.find(id) != objs.end();
    }

    ObjRef getObj(const Handle &id) const
    {
      Monitor crit(mutex);
      MethodTracker track (ObjMapping::getObj);
      if (!validObj(id))
      {
        throw InvalidHandle(id);
      }
      return objs.find(id)->second.second;
    }

    void addObj(auto_ptr<Object> obj)
    {
      Monitor crit(mutex);
      Handle h(obj->getID());

      // Stop iterator changes while container is being altered
      Monitor iter(iterMutex_);
      objs.insert(typename ObjHashMap::value_type(h, make_pair(0, ReferenceCounted<Object>::alloc(
          obj))));
    }

    // Will remove the given object from the cache
    // NOTE: This is a dangerous operation: it will block until there are no references to the
    // object other than the one in the cache, which opens many possibilities for deadlocks, 
    // and means that it is not safe to store references from the cache outside it.
    void removeObj(const Handle &id)
    {
      Monitor crit(mutex);
      ObjHashMapIterator entry = objs.find(id);
      if (entry != objs.end())
      {
        // If there are other references to the object wait for them to be released
        entry->second.second.ensureUnique();

        // Wait until no further iterators for this entry
        Monitor crit(iterMutex_);
        while (entry->second.first != 0)
        {
          iterBlock_.wait(iterMutex_);
        }

        objs.erase(entry);
      }
    }

    // Will remove the given object from the cache if the cache contains the only reference to it,
    // returns true only if the object is not in the cache
    bool releaseObj(const Handle &id)
    {
      Monitor crit(mutex);
      ObjHashMapIterator entry = objs.find(id);
      if (entry != objs.end())
      {
        Monitor crit(iterMutex_);
        if (entry->second.first != 0 || entry->second.second.references() != 1)
        {
          return false;
        }

        objs.erase(entry);
      }
      return true;
    }

    size_t size() const
    {
      return objs.size();
    }

    iterator begin()
    {
      Monitor crit(iterMutex_);
      MethodTracker track (ObjMapping::begin);
      return iterator(*this, objs.begin());
    }
    iterator end()
    {
      Monitor crit(iterMutex_);
      MethodTracker track (ObjMapping::end);
      return iterator(*this, objs.end());
    }

    void wake()
    {
      iterBlock_.broadcast();
    }

    Mutex &getIterMutex()
    {
      return iterMutex_;
    }

    void dump(ostream &out)
    {
      Monitor crit(mutex);
      out << Mapping cache contains  << objs.size() <<  base objects << endl;
    }

    // Will reload *all* objects from the cache
    // NOTE: This is a *VERY* dangerous operation: see comments above for removeObj
    void reload()
    {
      Monitor crit(mutex);

      // Delete all objects in cache
      ObjHashMapIterator i = objs.begin();
      while (i != objs.end())
      {
        // If there are other references to the object wait for them to be released
        i->second.second.ensureUnique();

        // Wait until no further iterators for this entry
        Monitor crit(iterMutex_);
        while (i->second.first != 0)
        {
          iterBlock_.wait(iterMutex_);
        }

        objs.erase(i++);
      }

      // Reload all objects from DB
      vector<Object *> base = initFunc();
      for (typename vector<Object *>::const_iterator i = base.begin(); i != base.end(); ++i)
      {
        Handle id = (*i)->getID();
        objs.insert(make_pair(id, make_pair(0, ReferenceCounted<Object>::alloc(
            auto_ptr<Object> (*i)))));
      }
    }

    static ObjMapping<Handle, Object, HashFunc, initFunc> &getTable()
    {
      static bool created = false;
      static Mutex createMutex;
      MethodTracker track (ObjMapping::getTable);
      static auto_ptr<ObjMapping<Handle, Object, HashFunc, initFunc> > theTable;
      if (!created)
      {
        Monitor crit(createMutex);
        if (!created)
        {
          theTable.reset(new ObjMapping<Handle, Object, HashFunc, initFunc> );
          created = true;
        }
      }
      return *theTable;
    }

  protected:
    friend class iterator;
    bool endIterator(ObjHashMapIterator &it)
    {
      return it == objs.end();
    }

    ObjMapping() :
      mutex(Mutex::Recursive)
    {
      vector<Object *> base = initFunc();
      objs.set_empty_key(0);
      for (typename vector<Object *>::const_iterator i = base.begin(); i != base.end(); ++i)
      {
        Handle id = (*i)->getID();
        objs.insert(make_pair(id, make_pair(0, ReferenceCounted<Object>::alloc(
            auto_ptr<Object> (*i)))));
      }
    }

  private:
    ObjMapping(const ObjMapping &);
    const ObjMapping &operator =(const ObjMapping &);

    mutable Mutex mutex;
    ObjHashMap objs;
    Mutex iterMutex_;
    Condition iterBlock_;
  };

A já jsem vytvořil dva objekty ven líbit,

typedef ObjMapping<RosterID, Roster, __gnu_cxx::hash<RosterID>, Roster::readAllRosters> RosterTable;
typedef ObjMapping<RosterHeaderID, RosterHeader, __gnu_cxx::hash<RosterID>, RosterHeader::readAllRosterHeaders> RosterHeaderTable;

Dvě metody soupiska :: readAllRosters & RosterHeader :: readAllRosterHeaders jsou databázové dotazy, které výtažky datové vrací jako vektoru.

Další předávání kód, který je příčinou pomalost je uveden níže,

for (RosterTable::iterator it = RosterTable::getTable().begin(); it != RosterTable::getTable().end(); ++it) {
  if (RosterHeaderTable::getTable().getObj( it->getHeader() )->getEmployee() == getID())
  {
    // Adding a roster to a map.
  }
}

Může někdo vidět něco, co lze udělat pro zlepšení tohoto kódu? Také si všimněte, že když to udělám komentář mimo if v kódu s překročením to běží v pohodě. A také můžete vidět v mapovém hash třídě, že jsem mutexd většina metod, které by mohly být příčinou mrtvé zámky. Prosím pomozte !

Položena 23/09/2010 v 09:00
zdroj uživatelem
V jiných jazycích...                            


4 odpovědí

hlasů
4

Co dělat metody ++ () a - () ve skutečnosti je třeba chránit? Pokud jsou dvě vlákna bude používat stejný iterátor? Musíte chránit mapy hash, nikoli iterátoru. Zamykání a odemykání jsou drahé operace. Odstranění této jistě zlepšit výkon.

Odpovězeno 23/09/2010 v 09:15
zdroj uživatelem

hlasů
2

Může někdo vidět něco, co lze udělat pro zlepšení tohoto kódu?

Váš threading / zamykání model je naivní. Existují nejméně čtyři problémy, které vidím.

  • Rekurzivní zamykání;
  • zablokování v každé členské funkce;
  • Chybí zamykání v některých funkcí;
  • jak použít funkci lokální statické proměnné není závit bezpečné.

Rekurzivní zamykání je optimální. Stojí to víc jednak proto, že složitější a proto, že jste získat exkluzivní přístup k více než jednou v jednom vlákně. Rekurzivní zamykání se lze vyhnout tím, že rozdělí realizaci veřejnému / front end a vnitřními / back end funkce. End funkce přední dělat zamykání a volání funkce koncového které neobsahují žádnou zamykání a nikdy volat jakékoliv front end funkce zpět.

Nicméně zamykání každé členské funkce je optimální, znovu. Mnoho operací pomocí kontejner bude muset zamknout / odemknout kontejneru několikrát během toho, co by mělo být (sémanticky) atomové operaci. Je také pravděpodobné, že nesprávná. Zatímco jednotlivé operace nad kontejneru jsou exkluzivní, stav kontejneru lze přepínat mezi těmito operacemi v způsobem, že kód není očekávat. Pokud víte / dokázat, že to není případ pro vás, používat externí zamykání po celé nádoby .

Také, alespoň size () chybí zámek.

Odpovězeno 23/09/2010 v 13:59
zdroj uživatelem

hlasů
0

Přichází se na to z jiného úhlu: Nevím, kam ukládat své ID zaměstnance, ale mohl byste dělat všechny tyto věci na DB již před vyplněním svůj RosterTable?

Odpovězeno 23/09/2010 v 10:05
zdroj uživatelem

hlasů
0

Máte hash mapy, ale chcete projít všechny prvky, ne?

Tak proč ne přidat další kontejner, který uchování dat v lineárním způsobem? Jako vektor nebo seznam?

Tímto způsobem můžete jen poskytovat iterátory, které jdou přes tento kontejner, když uživatel chce projít všemi prvky.

To jsou (nízké) náklady, ale to dělá věci rychle jednoduchým způsobem.

Odpovězeno 23/09/2010 v 09:50
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more