【问题标题】:boost multi_index_container and erase performance提升 multi_index_container 和擦除性能
【发布时间】:2010-05-14 00:29:59
【问题描述】:

我有一个 boost multi_index_container 声明如下,它由 hash_unique id(unsigned long) 和 hash_non_unique transaction id(long) 索引。元素的插入和检索速度很快,但是当我删除元素时,速度要慢得多。我希望它是恒定的时间,因为密钥是散列的。

例如从容器中删除元素

对于 10,000 个元素,大约需要 2.53927016 秒

对于 15,000 个元素,大约需要 7.137100068 秒

对于 20,000 个元素,大约需要 21.391720757 秒

这是我遗漏的东西还是预期的行为?

班级会议 { 民众: 会议() { //增加唯一id 静态无符号长计数器 = 0; boost::mutex::scoped_lock guard(mx); 计数器++; m_nId = 计数器; } 无符号长 GetId() { 返回 m_nId; } 长 GetTransactionHandle(){ 返回 m_nTransactionHandle; } …… 私人的: 无符号长 m_nId; 长 m_nTransactionHandle; boost::mutext mx; …… };
typedef multi_index_container<
  Session*,
  indexed_by< 
    hashed_unique< mem_fun<Session,unsigned long,&Session::GetId> >,
    hashed_non_unique< mem_fun<Session,unsigned long,&Session::GetTransactionHandle> >
    >  //end indexed_by
  > SessionContainer;
typedef SessionContainer::nth_index<0>::type SessionById;


int main() {
  ...
   SessionContainer container;
   SessionById *pSessionIdView = &get<0>(container);
   unsigned counter = atoi(argv[1]);
   vector<Session*> vSes(counter);
   //insert
   for(unsigned i = 0; i < counter; i++) {
     Session *pSes = new Session();
     container.insert(pSes); 
     vSes.push_back(pSes);
   }
   timespec ts;
   lock_settime(CLOCK_PROCESS_CPUTIME_ID, &ts);
   //erase
   for(unsigned i = 0; i < counter; i++) {
      pSessionIdView->erase(vSes[i]->getId());
      delete vSes[i];
   }
   lock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
   std::cout << "Total time taken for erase:" << ts.tv_sec << "." << ts.tv_nsec << "\n";
   return (EXIST_SUCCESS);
}

【问题讨论】:

  • 你试过分别定时删除和擦除吗?
  • 是的。删除不需要太多时间。事实上,我在内部使用 boost::object_pool 来构造和破坏对象。所以没有分配/解除分配的开销。为了简单起见,我只是在这里使用“删除”。
  • 各种第二索引类型的性能测试结果链接。 joshitech.blogspot.com/2010/05/…
  • @rjoshi,性能测试结果在某处仍然可用吗?你的博客链接失效了。谢谢!

标签: boost


【解决方案1】:

在您的测试代码中,m_nTransactionHandledo Session 对象接收什么值?可能所有对象的值都相同吗?如果是这样,擦除将花费很长时间,因为当有 许多 个相等元素时,散列容器的性能很差。尝试在创建时分配不同的 m_nTransactionHandle 值,看看这是否会加快您的测试速度。

【讨论】:

  • 感谢您的提示。是的,m_nTransactionHandle 的可能性可能是相同的值,这就是我将它用作 hash_non_unique 的原因。但是主索引 m_nId 是 hashed_unique ,我正在使用它从容器中擦除。我认为在通过主散列索引擦除条目时,非唯一/辅助索引值不应该影响性能。无论如何,我会尝试一下并告诉你。
  • 你是绝对正确的。如果我将所有两个索引都设为 hashed_unique,则性能几乎是恒定的。我什至尝试将第二个索引设为ordered_unique 和ordered_non_unique,性能几乎相同。所以我想知道为什么第二个 hashed_non_unique 失去了性能事件,尽管我使用 hash_unique 键来删除对象。我认为要么是错误,要么是设计缺陷。
【解决方案2】:

擦除元素时,性能是构成容器的所有索引的函数(基本上,必须从 每个 索引中擦除元素,而不仅仅是您当前使用的索引) .当有许多等效元素时,散列索引会受到严重伤害,这不是它们设计用来反对的模式。

【讨论】:

    【解决方案3】:

    我刚刚发现 hashed_non_unique 与 hashed_unique 对于第二个索引的性能几乎相同,除了检查重复的轻微开销。

    瓶颈在于 boost::object_pool。我不知道内部实现,但它似乎是一个列表,它遍历列表以查找对象。性能结果和源代码见链接。

    http://joshitech.blogspot.com/2010/05/boost-object-pool-destroy-performance.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多