【问题标题】:Performance brute force hashing C++ Java [closed]性能蛮力散列 C++ Java [关闭]
【发布时间】:2014-12-27 11:15:44
【问题描述】:

我在 C++ 和 Java 中都为 md5 实现了一个暴力破解器,并且对为什么它们的效率会有所不同存在疑问。
数据和复杂度图(密码的 E^长度)与时间的关系在这里:http://i.imgur.com/hckCe8f.png
密码是简单的“b”重复以填充长度

在 C++ 中,我使用了 md5 的这个实现:zedwood.com/article/cpp-md5-function
在 Java 中,我使用了这个站点上的第二个实现:http://www.asjava.com/core-java/java-md5-example/

在递归 C++ 实现中,我的循环代码是在一个单独的类中完成的:

class bruteChar {
    string charset;
    char last_char;
    string str;
    string double_start;
    char reverse_charset[256];
  private:
    string next(string s)
    {
        size_t length = s.size()-1;
        if(length == 0)
        {
            if( s[0]==last_char)
                return double_start;
            return string(1, charset[reverse_charset[s[length]]+1]);
        }
        if(s[length] == last_char)
            return next(s.substr(0,length))+charset[0];
        else
            return str.substr(0,length)+string(1, charset[reverse_charset[s[length]]+1]);
    };

  public:
    void start (string chars)
    {
        charset = chars;
        str=charset[0];
        last_char=charset[charset.size()-1];
        double_start=charset[0];
        double_start+=charset[0];

        for(size_t i = 0; i < charset.size(); ++i)
            reverse_charset[charset[i]]=i;
        reverse_charset[charset[charset.size()]]=0;
    }

    string next()
    {
        str=next(str);
        return str;
    }
};

在 Java 中我使用了一个自定义类

public class picochar {
    public static char[] charset = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); 
    int num;
    int mod;

    picochar(int init, int mod)
    {
        num = init%mod;
    }

    picochar(char init, int mod)
    {
        for(int i = 0; i < mod; i++)
        {
            if(charset[i] == init)
                num = i;
        }  
    }

    public char get()
    {
        return charset[num];
    }

    public boolean equals(char  ch)
    {
        return (get() == ch);
    }

    public void increment()
    {
        num++;
    }
}

还有下面的方法

public static String next(String s) {
    int length = s.length();
    picochar pc = new picochar(s.charAt(length - 1),mod);
    if(pc.equals(picochar.charset[mod-1]))
        return length > 1 ? next(s.substring(0, length - 1)) + 'a' : "aa";
    pc.increment();
    return s.substring(0, length - 1) + pc.get();
}

为什么 Java 在计算哈希方面比 C++ 更高效?
我是不是简单地为 Java 使用了一个高效的 MD5 实现,而为 C++ 使用了一个糟糕的实现?
我认为 C++ 会比 Java 快得多,因为 Java 必须通过 JVM 运行所有内容,而 C 则在本地完成。

然而,Java 远胜过 C++ 解决方案。如果这仅仅是因为我的 C++ 程序编码不佳,我将如何解决这个问题?

编辑删除了不同的 C++ 程序,现在两个解决方案都递归循环。

我计算了在没有散列的情况下循环需要多长时间,这里 Java 的速度是 C 的两倍,@Dunes 对此进行了解释。当重新编码为不递归使用 substr() 而是改变原始字符串时,C 的速度大约是 Java 的两倍。

我对“hello”1 在经过几秒钟的哈希运算后,C++ 会获得类似的性能提升,但提升幅度远不及 Java。

那么为什么 Java 的预热效果更好?

【问题讨论】:

  • 我会尽量让代码更相似。 C++ 和 Java 看起来不应该如此不同。这些差异很可能解释了性能差异。
  • 好吧,正如您所说,您需要比较相同的实现。如果操作正确,C++ 通常可能会更快。附带说明:这不仅仅是因为 JIT。
  • 另一个区别是您使用不同的 MD5 库,这是您的程序应该花费更多时间的地方。在查看您的代码之前,我会尝试查看这些库的性能比较。
  • C/C++ 比 Java 快是一个神话。如果您编写相同的东西,运行时间将是相同的(由于其内部优化,在 Java 上可能更快)。声称 C/C++ 更快的人要么在使用优化的库,要么在编写糟糕的 Java 代码。

标签: java c++ performance md5 brute-force


【解决方案1】:

看起来 c++ 实现如此缓慢的原因是因为您正在按值传递字符串。也就是说,每次您使用字符串参数调用方法或返回字符串时,程序都必须对整个字符串进行全新的复制。

然而,因为 Java 有不可变的字符串,它可以绕过传递同一字符串的不同视图。 String.substring 不复制支持字符数组。相反,新的字符串对象只是跟踪与后备字符数组相关的起始索引和长度。如果不明智地使用子字符串,它可能会导致内存泄漏 - 只要存在,单字符视图将使原始的百万字符后备数组保持活动状态。

【讨论】:

  • 啊!我试图使这两个循环尽可能相似,但不知道它们是如何运作的。
【解决方案2】:

原来我使用的是低效的 md5 实现。
这是计算 227 哈希所花费的时间与 openssl 所花费的时间

openssl v1
17.4911

openssl v2
14.9546

custom
291.201

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    • 2017-08-19
    • 1970-01-01
    相关资源
    最近更新 更多