python足够聪明,可以用常量结果替换函数调用吗?

时间:2016-08-05 21:53:44

标签: python c performance optimization apache-spark

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

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
   ...:         

甚至在分钟之后完成,我知道列表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()的参考并没有说任何可以向我解释此事的内容,但我想的是它可能需要查看分区来做到这一点,但那不应该&情况确实如此,因为sizes list ,而不是 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's方法。

1 个答案:

答案 0 :(得分:5)

我绝不是蟒蛇内部运作方面的专家,但从我的理解到目前为止你想比较的速度

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中是一个固定的大小,它可以找到min值而不是python列表的开销,因此我认为它在C中没有问题(以及C)是一种低级语言。)

同样,我不完全理解python的底层代码和编译,并且我确定如果你在python中分析循环的过程,你会看到python反复计算{{ 1}},导致极端延迟。我希望更多地了解python的内部工作原理(例如,是否有任何方法在python的循环中缓存,或者每次迭代都会再次计算所有内容?)所以如果有人有更多的信息和/或更正,让我知道!