【问题标题】:Are the Performances of these two programs the same?这两个节目的表演是一样的吗?
【发布时间】:2021-02-16 01:03:12
【问题描述】:

例如,假设您有一个链表 1->2->3->4->5->6->NULL 并且您想要计算该链表的偶数索引的总和(假设第一个index从1开始,链表大小为偶数)

第一种方法

int total = 0;
int count = 0;
Node *ptr = head;
while(ptr != NULL)
{
    if(count % 2 == 0)
     {
       total += ptr->data;
     }
     count++;
     ptr = ptr->next;
}
 

第二种方法

int total = 0;
Node *ptr = head;
while(ptr != NULL)
{  
    total += ptr->data;
     ptr = ptr->next->next;
}

那么在我做了这两种方法之后,它们的性能是否相同?

【问题讨论】:

  • 如果有奇数个节点,第二种方法很容易出现未定义的行为。
  • 测量它,但请注意,如果不是本示例之外的内容,遍历整个链表可能会大大超过差异。
  • 如果您测量创建 10,000 个节点,然后使用 std::chrono 对两种算法进行计时。确保您使用的是优化/发布版本。时序相关:https://en.cppreference.com/w/cpp/chrono/high_resolution_clock/now
  • 第二个可能会稍微(非常稍微)快一些,而且安全性会无限降低。
  • 您可以将操作展开为while (ptr) { total += ptr->data; ptr = ptr->next; if (ptr) ptr = ptr->next; },这基本上节省了加法、模数和寄存器,但保持了相同数量的分支。也许一个聪明的优化编译器无论如何都会这样做。我认为这是过早的优化,正如其他人已经引用的那样,由于缓存未命中的机会增加,链表遍历通常很慢。最后,要么使用您的第一个示例,要么使用我的 - 选择应该主要是使用最清楚地向任何阅读代码的人描述意图的示例。

标签: c++ performance linked-list singly-linked-list


【解决方案1】:

我再次阅读了您的问题,并会回答 可能第二种方法稍微快一些。

现在,cmets 部分立即强调它也更危险。您实际上已指定假设列表中的节点数是偶数。如果这是一个有保证且可执行的前提条件,那么在技术上这样做是可以的。

即使是一个聪明的优化编译器也无法知道这个偶数列表长度的前提条件,所以它可能实现的最好的结果是认识到count 仅用于控制total 是否被更新等等循环可以展开如下:

// Possible automatic compiler optimization of First Approach
while (ptr)
{
    total += ptr->data;
    ptr = ptr->next;

    // Skip over every second node
    if (ptr) ptr = ptr->next;
}

基本而言,我们现在拥有的每个循环迭代比您的第二种方法多一个指针测试(分支)。这会产生更多指令(特别是分支指令),因此代码在技术上会(稍微)慢一些。

当然,这带来的实际影响可能很小。您的主要瓶颈是指针间接并从内存中获取,而不是指针测试本身。如果每个节点使用的内存大部分不是连续的,那么您将在大型列表上遇到缓存问题(实际上这会影响性能大约 100 倍)。

以上所有内容我的意思是,基于偶数列表长度的前提条件的特殊优化的好处是收益递减。

考虑到它本质上是不安全的,除非在代码中有很好的记录和/或受列表“均匀性”测试保护(如果您将节点数存储在某处),我建议使用您的第一种方法进行防御性编码或使用我的等效和(可以说)更整洁的版本。

【讨论】:

  • 我想对您的第一种方法添加一个警告。实际上,“展开”版本比您的两种方法中的任何一种都更安全,因为它不依赖于计数变量,如果您有一个非常大的列表导致未定义的行为(或至少是特定于实现的行为),则该变量可能会溢出。值溢出。当然,它不依赖于列表的长度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-19
  • 2011-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-23
相关资源
最近更新 更多