【问题标题】:Python lists vs C arrays : 100x slower? [closed]Python 列表 vs C 数组:慢 100 倍? [关闭]
【发布时间】:2023-04-06 12:12:01
【问题描述】:

据我了解,Python 列表是作为向量实现的。这就是为什么我无法解释为什么以下代码在 Python 中比等效的 C 代码慢 100 倍(在 3.1.3 中,而在 python 3.2 中“仅”65 倍)。

它只是重复提取列表的最大值,nbExtract 次:

nbValues = int(input())
nbExtract = int(input())
values = [int(value) for value in input().split()]

for loop in range(nbExtract):
   idMax = 0   
   for idValue in range(nbValues):
      if values[idMax] < values[idValue]:
         idMax = idValue
   print(values[idMax], end = ' ')
   values[idMax] = values[nbValues- 1]
   nbValues= nbValues - 1

注意nbExtract 可以小于 log(nbValues),因此对值进行排序通常较慢

我知道如何更快地做到这一点(例如使用内部 max 函数),但这是针对高中生的练习,我们只教他们基础知识(if/else、for、while 和 lists) ,而不是 Python 中可用的所有函数。

有没有办法在保持相同结构的同时提高速度?我试过 Python 的数组,但速度差不多。

有谁知道为什么在内部 Python 处理列表的速度要慢得多?


根据要求,等效的 C 代码:
#include <stdio.h>
int main()
{
   int nbValues, nbExtract ;
   scanf("%d%d", &nbValues, &nbExtract);
   int values[nbValues];
   for (int idValue = 0; idValue < nbValues; idValue++)
      scanf("%d", &values[idValue]);

   for (int loop = 0; loop < nbExtract; loop++)
   {
      int idMax = 0;
      for (int idValue = 0; idValue < nbValues; idValue++)
         if (values[idMax] < values[idValue])
            idMax = idValue;
      printf("%d ", values[idMax]);
      values[idMax] = values[nbValues - 1];
      nbValues--;
   }
   return 0;
}

【问题讨论】:

  • 你能发布等效的 C 代码吗?
  • Python 是否检查所有数组访问的越界情况?
  • 另外,慢 100 倍有关系吗?
  • 恕我直言,Python 只是比 C 更好地暴露了算法的缓慢性
  • 我很困惑 .. 你在教 Python 但你不知道它是如何工作的?

标签: python c arrays performance list


【解决方案1】:

编辑:暂且不提,我显然没有在这里说话。我的印象是 Python 的列表几乎就是链表,但事实并非如此。

Python 的list 类型并不完全是一个数组,至少在您考虑数组/向量的意义上不是。 list 类型更像是一个链表数据结构(易于插入、追加、删除元素等),尽管这也不是一个完全准确的描述。为了与 C 数组进行公平比较,我建议使用 Numpy 中的 array 类型。

更多信息请看这里:Python List vs. Array - when to use?

【讨论】:

  • list 也可以包含任意类型。
  • 然而访问时间是 O(1) (stackoverflow.com/questions/3917574/…) 所以不是我的链表
  • list 类型根本不是链表。它是一个可调整大小的数组
【解决方案2】:

您可以通过细微的调整来缩短几秒钟的时间。

def main():
    nbValues = int(input())
    values = [int(x) for x in input().split()]

    for loop in range(nbValues):
        idMax = 0   
        maxv = -2**64 # Not perfect
        for idValue in range(nbValues):
            v = values[idValue]
            if v > maxv:
                idMax = idValue
                maxv = v
        print(values[idMax], end = ' ')
        values[idMax] = values[nbValues- 1]
        nbValues = nbValues - 1

main()

我做了两个小改动。

  1. 我将整个代码块包装在一个函数中。功能块内的代码比顶层代码更快,因为变量查找可以通过索引而不是通过在全局字典中查找变量名来完成。改进:在我的计算机上速度提高了 60%。

  2. 然后,我通过将当前最大值缓存在局部变量中来减少数组访问次数。这将速度进一步提高了 15%。

我尝试使用array 模块,但它没有提供进一步的收益。我并不感到惊讶,因为访问数组对象中的整数需要堆分配。

一般而言,Python 开发人员并不关心优化 Python 以处理此类代码,他们提供了很好的理由。如果不求助于内置功能,我不会期望任何进一步的改进。例如,以下代码在我系统上的 C 版本的 3 倍以内,并且与 Python 程序员的编写方式相匹配。

nbValues = int(input())
values = [int(x) for x in input().split()]
values.sort(reverse=True)
print(' '.join(str(x) for x in values))

建议:减小输入大小。将数组大小减半可以免费提高 300% 的速度。

【讨论】:

  • 感谢您的建议。如果只需要 top X 值,你会怎么做? (但即使在这种情况下,您的解决方案通常也比使用两个“for”更快,使用内部函数的好处是巨大的)。我认为我们将减少测试规模并为高级学生教授更好的 Python。
  • 在 Python 中,如果我只需要前 X 值,那么我可能无论如何都会对整个列表进行排序。程序员工作量和代码复杂性的巨大收益不值得执行速度的最小收益。 (也许这就是教训?)
猜你喜欢
  • 2015-09-07
  • 2021-05-30
  • 2018-05-27
  • 2015-03-28
  • 2015-12-04
  • 1970-01-01
  • 2010-10-14
  • 1970-01-01
  • 2021-11-28
相关资源
最近更新 更多