为什么Java比C ++更快地读取大文件?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (13)

我有一个2 GB的文件(iputfile.txt),文件中的每一行都是一个单词,就像:

apple
red
beautiful
smell
spark
input

我需要编写一个程序来读取文件中的每个单词并打印出单词数量。我使用Java和C ++编写它,但结果令人惊讶:Java运行速度比C ++快2.3倍。我的代码如下所示:

C ++:

int main() {
    struct timespec ts, te;
    double cost;
    clock_gettime(CLOCK_REALTIME, &ts);

    ifstream fin("inputfile.txt");
    string word;
    int count = 0;
    while(fin >> word) {
        count++;
    }
    cout << count << endl;

    clock_gettime(CLOCK_REALTIME, &te);
    cost = te.tv_sec - ts.tv_sec + (double)(te.tv_nsec-ts.tv_nsec)/NANO;
    printf("Run time: %-15.10f s\n", cost);

    return 0;
}

输出:

5e+08
Run time: 69.311 s

Java的:

 public static void main(String[] args) throws Exception {

    long startTime = System.currentTimeMillis();

    FileReader reader = new FileReader("inputfile.txt");
    BufferedReader br = new BufferedReader(reader);
    String str = null;
    int count = 0;
    while((str = br.readLine()) != null) {
        count++;
    }
    System.out.println(count);

    long endTime = System.currentTimeMillis();
    System.out.println("Run time : " + (endTime - startTime)/1000 + "s");
}

输出:

5.0E8
Run time: 29 s

在这种情况下,为什么Java比C ++更快,以及如何提高C ++的性能?

提问于
用户回答回答于

你没有比较相同的东西。Java程序根据换行符读取行,而C ++程序读取由空格分隔的“单词”,这是一项额外的工作。

尝试istream::getline

后来

你也可以尝试做一个基本的读取操作来读取一个字节数组并扫描这个换行符。

甚至更晚

在我的旧版Linux笔记本上,与C ++ getline相比,jdk1.7.0_21和老告别4.3.3差不多。(我们已经确定阅读单词比较慢。)-O0和-O2之间没有太大区别,考虑到循环中代码的简单性,这并不让我感到意外。

最后一点 正如我所建议的那样,LEN = 1MB的fin.read(buffer,LEN)并使用memchr扫描'\ n'会导致另一个速度提高约20%,这使得C(没有任何C ++剩下的现在)比Java更快。

用户回答回答于

在语言处理方式上有许多显著的差异。I/O,所有这些都能带来不同的结果。

也许第一个(也是最重要的)问题是:如何将数据编码在文本文件中。如果是单字节字符(ISO 8859-1或乌特夫-8),则Java必须将其转换为乌特夫-16在处理之前,根据区域设置,C++也可能(或不)转换或执行一些附加检查。

正如已经指出的(至少部分),在C++中,>>使用特定于区域设置的isspace,,,getline会简单地比较'\n',这可能更快。的典型实现isspace将使用位图,这意味着对每个字符都有额外的内存访问。)

优化级别和特定库实现也可能有所不同。在C++中,一个库的实现速度比另一个库快2到3倍,这并不少见。

最后,一个最显著的区别是:C++区分了文本文件和二进制文件。您已经以文本模式打开了该文件;这意味着它将在最低级别进行“预处理”,甚至在提取操作符看到它之前。这取决于平台:对于Unix平台,“预处理”是不操作的;在Windows上,它将把crlf对转换为'\n',这将对性能产生一定的影响。如果我记得是正确的(我已经几年没有使用Java了),Java期望更高级别的函数来处理这个问题,所以像这样的函数readLine会稍微复杂一些。只是在这里猜测一下,但我怀疑在较高级别上的附加逻辑在运行时的开销比在较低级别上的缓冲区预处理成本要低。(如果您在Windows下进行测试,则可以尝试在C++中以二进制模式打开文件。当您使用>>任何额外的CR将被视为空白。带着getline,您将不得不添加逻辑以删除任何尾随'\r'到您的代码)。)

扫码关注云+社区