【问题标题】:C - Is sorting an array of pointers of structs slower than sorting the structs directly (qsort)C - 对结构指针数组进行排序比直接对结构进行排序要慢(qsort)
【发布时间】:2016-11-29 06:35:09
【问题描述】:

我正在使用标准 c 库的 qsort 函数对数百万个组织在一个数组中的结构进行排序。我试图通过创建具有相同长度的结构指针数组来优化性能。与我的预期相反,第二个变体的执行时间更慢:

qsort 一个结构数组:199s qsort 结构指针数组:204

我预计在内存中交换指针块的时间会比移动结构(大小 576)更快。我可能有任何性能泄漏或这是已知行为吗?

【问题讨论】:

  • 你必须测量它,通过在调用排序方法之前和之后调用time(3)
  • 是否有可能使用 qsort 对结构数组进行排序已经交换了指针而不是结构?
  • 另外 5 秒是 2.5% 的差异,这可能在您的误差范围内。
  • 不,qsort 将移动结构(如果这是你告诉它的)。您需要显示代码。特别是,如果比较函数所花费的时间比移动结构的时间大,那么指针数组将无济于事。
  • 发布代码。没有代码(并向我们展示您的具体测量值),这是毫无意义的。

标签: c arrays pointers struct qsort


【解决方案1】:

这里还有其他问题。

通过创建指针数组,您将内存碎片化。标准库中的算法旨在优化连续数组的排序,因此与只有更大的数组相比,这样做可能会更频繁地丢失缓存。

特别是快速排序对于引用的局部性非常有用,因为您将样本大小减半,因此最终您将原始数组的子集以可以完全放入缓存的块中进行排序。

作为一般规则,缓存未命中比命中慢一个数量级。因此,此时间延迟可能足以弥补您通过不复制所有字节而获得的速度提升。

【讨论】:

    【解决方案2】:

    快速排序的工作方式是通过将相邻元素靠得更近来逐渐重新组织数组。这允许数据缓存更有效地工作,算法越接近最终结果。

    如果您转换为指针数组,那么数据访问可能会变慢,因为结构保持其“未排序”顺序,而它们的指针正在排序。但是,比较结构需要跟踪指向它们“未排序”实例的指针,这可能会导致数据缓存未命中。

    要实现您想要的结果,您可以为您的数据创建一个索引结构。索引结构将保存排序键(或它的副本)。

    struct index_type {
        key_type key;
        data_type *data;
    };
    

    现在,您将对index_type 的数组进行排序,而不是对data_type 的指针数组进行排序。由于键存储在数组本身中,因此您避免了跟随指向“未排序”结构的指针的问题。

    【讨论】:

      【解决方案3】:

      我使用这个结构做了一个快速的完整性检查(当int 是 32 位时,它的大小为 576)

      struct test
      {
          int value;
          char data[572];
      };
      

      我用这段代码初始化了一个由 100 万个结构组成的动态分配数组

      for ( int i = 0; i < count; i++ )
      {
          array[i].value = rand();
          for ( int j = 0; j < 572; j++ )
              array[i].data[j] = rand();
      }
      

      我用这段代码对数组进行了排序

      int compare( const void *ptr1, const void *ptr2 )
      {
          struct test *tptr1 = (struct test *)ptr1;
          struct test *tptr2 = (struct test *)ptr2;
          return tptr1->value - tptr2->value;
      }
      
      int main( void )
      {
          int count = 1000000;
          ...
          qsort( array, count, sizeof(struct test), compare );
          ...
      }
      

      初始化数组的时间是 4.3 秒,排序数组的时间是 0.9 秒。

      然后我修改了代码以创建指向结构的指针数组,并对指针数组进行排序。初始化时间还是4.3秒(大部分初始化时间是由于调用rand()5亿次)。对指针数组进行排序需要 0.4 秒。对指针数组排序比直接对结构体数组排序快一倍多。

      所以我的结论是,您的代码有一些与qsort 无关的严重低效率。

      【讨论】:

        【解决方案4】:

        通常,哪个更快取决于结构的大小。对于与指针大小相同的结构,显然对结构进行排序比对指向结构的指针进行排序要快。随着结构大小的增加,将达到相反的情况(想象对一个 1 MB 结构的数组进行排序:您将大部分时间花在 memcopy() 中)。确切地说,这一点在哪里取决于代码无法控制的事情(缓存结构、缓存大小等)。如果这对您很重要,那么您最好进行实验和衡量。

        【讨论】:

          猜你喜欢
          • 2014-07-04
          • 1970-01-01
          • 1970-01-01
          • 2014-05-21
          • 2021-08-02
          • 2015-12-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多