【问题标题】:Is python smart enough to replace function calls with constant result?python 是否足够聪明,可以用恒定结果替换函数调用?
【发布时间】:2023-03-20 07:05:01
【问题描述】:

来自 的美丽世界,我正在努力理解这种行为:

In [1]: dataset = sqlContext.read.parquet('indir')
In [2]: sizes = dataset.mapPartitions(lambda x: [len(list(x))]).collect()
In [3]: for item in sizes:
   ...:     if(item == min(sizes)):
   ...:         count = count + 1
   ...:         

不会甚至在 20 分钟之后完成,而且我知道sizes 的列表并没有那么大,长度不到 205k。然而,这立即执行

In [8]: min_item = min(sizes)

In [9]: for item in sizes:
    if(item == min_item):
        count = count + 1
   ...:         

那么发生了什么?

我的猜测: 无法理解 min(sizes) 将始终保持不变,因此在前几次调用之后替换为它的返回值..因为 Python 使用解释器..


min() 的引用没有说任何可以向我解释这件事的内容,但我在想的是它可能需要查看分区才能做到这一点,但这不应该是情况,因为sizeslist,而不是 RDD


编辑:

这是我困惑的根源,我用 C 写了一个类似的程序:

for(i = 0; i < SIZE; ++i)
    if(i == mymin(array, SIZE))
        ++count;

得到了这些时间:

C02QT2UBFVH6-lm:~ gsamaras$ gcc -Wall main.c
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out
That took 98.679177000 seconds wall clock time.
C02QT2UBFVH6-lm:~ gsamaras$ gcc -O3 -Wall main.c
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out
That took 0.000000000 seconds wall clock time.

对于时间安排,我使用了 Time measurements 中的 Nomimal Animal 方法。

【问题讨论】:

  • 第一个代码是O(n*n),第二个代码是O(n)。这如何支持这个假设?
  • CPython 只做非常简单的优化。语言的动态特性也使得许多优化变得不可能:例如,想象一下如果其他代码做了min = lambda x: 1
  • 我所知道的任何非纯语言都不会尝试“理解”这种优化。要使其有效,就需要确定性行为的保证。
  • 我什至不相信 C 编译器会执行这种优化,更不用说 Python。优化器必须考虑太多奇怪的可能性。
  • @user2864740 对你说是因为[1] 和 [2]?

标签: c python python c performance optimization apache-spark


【解决方案1】:

我绝不是python内部工作原理的专家,但根据我目前的理解,你想比较一下它的速度

for item in sizes:
    if(item == min(sizes)):
        count = count + 1

min_item = min(sizes)
for item in sizes:
    if(item == min_item):
        count = count + 1

如果我有任何错误,现在有人纠正我,但是,

在 python 中列表是可变的并且没有固定长度,并且被视为这样,而在 C 中,数组具有固定大小。来自this question

Python 列表非常灵活,可以保存完全异构的任意数据,并且可以在摊销的常数时间内非常有效地附加它们。如果您需要高效且轻松地缩小和扩展阵列,那么它们就是您的最佳选择。但是它们比 C 数组使用更多的空间。

现在举这个例子

for item in sizes:
    if(item == min(sizes)):
        new_item = item - 1
        sizes.append(new_item)

那么item == min(sizes) 的值在下一次迭代中会有所不同。 Python 不会缓存 min(sizes) 的结果值,因为它会破坏上面的示例,或者需要一些逻辑来检查列表是否已更改。相反,它由您决定。通过定义min_item = min(sizes),您实际上是在自己缓存结果。

现在由于数组在 C 中是固定大小的,它可以找到比 python 列表更少的开销的最小值,因此我 认为 它在 C 中没有问题(以及 C是一种低级语言)。

再一次,我对python的底层代码和编译不是很了解,而且我敢肯定,如果你分析了python中循环的过程,你会看到python重复计算min(sizes),导致极端数量的滞后。我很想了解更多关于 python 的内部工作原理(例如,是否有任何方法缓存在 python 的循环中,或者是否为每次迭代重新计算所有内容?)所以如果有人有更多信息和/或更正,请告诉我知道!

【讨论】:

  • 虽然您有观点并且我接受了您的回答,但请注意,我认为这不是 100% 清楚的。例如,我只是对std::vector 做了同样的思考,得到了 115.9 秒。和 8.4 秒,尽管向量具有灵活性,但它显示出显着的加速。所以,我想说这是python 的事情,而不是数据结构的灵活性问题..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
  • 2012-02-26
  • 1970-01-01
  • 2015-05-21
  • 2013-11-03
相关资源
最近更新 更多