首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >我的python程序比同一程序的java版本执行得更快。怎么回事?

我的python程序比同一程序的java版本执行得更快。怎么回事?
EN

Stack Overflow用户
提问于 2009-05-27 22:48:42
回答 19查看 3.8K关注 0票数 15

更新: 2009-05-29

谢谢你所有的建议和建议。我采纳了你的建议,让我的产品代码平均执行速度比几天前我的最佳结果快了2.5倍。,最后,我能够让代码变得最快。

课程:

  • 我下面的示例代码显示了原语int的插入,但生产代码实际上是存储字符串(我的错)。当我纠正python执行时间从2.8秒增加到9.6秒时。所以一开始,java在存储对象时实际上速度更快。
  • ,但它并没有止步于此。我一直在执行java程序,如下所示:

java -Xmx1024m SpeedTest

但是,如果您按如下方式设置初始堆大小,您将获得巨大的改进:

代码语言:javascript
复制
java -Xms1024m -Xmx1024m SpeedTest

这个简单的更改将执行时间减少了50%以上。所以我的SpeedTest的最终结果是Python9.6秒。Java 6.5秒。

原始问题:

我有以下python代码:

代码语言:javascript
复制
import time
import sys

def main(args):    
    iterations = 10000000
    counts = set()
    startTime = time.time();    
    for i in range(0, iterations):
        counts.add(i)
    totalTime = time.time() - startTime
    print 'total time =',totalTime
    print len(counts)

if __name__ == "__main__":
    main(sys.argv)

它在我的机器上执行大约3.3秒,但我想让它更快,所以我决定用java编写它。我假设因为java是编译的,并且通常被认为比python更快,所以我会看到一些很大的回报。

下面是java代码:

代码语言:javascript
复制
import java.util.*;
class SpeedTest
{    
    public static void main(String[] args)
    {        
        long startTime;
        long totalTime;
        int iterations = 10000000;
        HashSet counts = new HashSet((2*iterations), 0.75f);

        startTime = System.currentTimeMillis();
        for(int i=0; i<iterations; i++)
        {
            counts.add(i);
        }
        totalTime = System.currentTimeMillis() - startTime;
        System.out.println("TOTAL TIME = "+( totalTime/1000f) );
        System.out.println(counts.size());
    }
}

所以这段java代码基本上和python代码做了同样的事情。但它的执行时间是8.3秒,而不是3.3秒。

我从一个真实的例子中提取了这个简单的例子来简化事情。关键的元素是我有(set或hashSet),它有很多成员,就像这个例子一样。

以下是我的问题:

  1. 为什么我的python实现比java implementation?
  2. Is更快有比hashSet ( java )更好的数据结构来保存唯一的collection?
  3. What会使python实现更快?
  4. 什么能让java实现更快?

更新:

感谢到目前为止做出贡献的所有人。请允许我补充一些细节。

我没有包含我的产品代码,因为它相当复杂。会让人分心。我上面给出的例子是最简单的。我的意思是,java put调用似乎比python set`s的add()慢得多。

产品代码的java实现也比python版本慢2.5 -3倍--就像上面一样。

我不关心vm预热或启动开销。我只想将startTime中的代码与totalTime中的代码进行比较。请不要为其他事情操心。

我使用了足够多的存储桶来初始化哈希集,这样它就永远不需要重新进行哈希了。(我总是提前知道集合最终将包含多少元素。)我想有人会争辩说,我应该把它初始化为iterations/0.75。但是如果你尝试一下,你会发现执行时间没有明显的影响。

我为那些好奇的人设置了Xmx1024m (我的机器有4 4GB的内存)。

我使用的是java版本: Java(TM) SE Runtime Environment (build 1.6.0_13-b03)。

在生产版本的中,我在hashSet中存储了一个字符串(2-15个字符),所以我不能使用原语,尽管这是一个有趣的情况。

我已经运行代码很多很多次了。我有很高的信心,python代码比java代码快2.5到3倍。

EN

回答 19

Stack Overflow用户

发布于 2009-05-28 09:26:12

您实际上并不是在测试Java和Python,而是使用自动装箱的整数和Python的原生集合和整数处理来测试java.util.HashSet

显然,在这个特定的微基准测试中,Python端确实更快。

我尝试用来自GNU troveTIntHashSet替换HashSet,获得了3到4倍的加速比,使Java略微领先于Python。

真正的问题是,您的示例代码是否真的像您认为的那样代表您的应用程序代码。您是否运行过分析器,并确定大部分CPU时间都花在将大量in放入HashSet中?如果不是,这个例子就无关紧要了。即使唯一的区别是您的生产代码存储的是in以外的其他对象,它们的创建和hashcode的计算也很容易支配set插入(并完全破坏Python在特别处理in方面的优势),从而使整个问题变得毫无意义。

票数 21
EN

Stack Overflow用户

发布于 2009-05-28 08:46:55

我怀疑这是因为Python使用整数值本身作为其哈希,而基于哈希表的set实现直接使用该值。从source中的注释

这不一定是坏事!相反,在大小为2**i的表中,将低阶i位作为初始表索引是非常快的,并且对于由连续的int范围索引的dict根本不存在冲突。当键是“连续”字符串时,情况也大致相同。因此,在常见情况下,这提供了比随机更好的行为,这是非常可取的。

此微基准测试在某种程度上是Python的最佳情况,因为它恰好会导致零散列冲突。然而,如果Javas HashSet重新散列密钥,它必须执行额外的工作,并且在冲突中的行为也会变得更糟糕。

如果将范围(迭代)存储在一个临时变量中,并在循环之前对其执行random.shuffle,则运行时会慢2倍以上,即使随机播放和列表创建是在循环之外完成的。

票数 12
EN

Stack Overflow用户

发布于 2009-05-27 23:06:53

另一种可能的解释是,Python中的集合是在C代码中本地实现的,而Java中的HashSet是在Java本身中实现的。因此,Python中的集合应该会更快。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/918359

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档