当考虑性能时如何从文件中读取整数?

3

我正在CodeEval上完成一些任务。基本上,任务非常简单:“打印出从文件中读取的所有整数的总和”。

我的解决方案如下:

import java.io.File;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;

public class SumIntegersFromFile {

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

        File file = new File(args[0]);
         BufferedReader br = new BufferedReader( new FileReader(file));
         String line;
         int i=0;
         while((line=br.readLine())!=null){
            int k = Integer.parseInt(line);
             i+=k;
         }
         br.close();
         System.out.println(i);
    }
}

但是我被告知这个解决方案在性能方面并不是最佳的。

该代码基于问题“Best way to read a text file”中的建议。这里唯一的区别是我读取的是整数而不是字符串。

在Java中,从文件中读取整数的最高性能方法是什么?


3
“我只得到了29.352分(35分满分)”这句话是什么意思? - BitNinja
9
这个问题似乎不适合此处,因为它涉及到改进工作代码。建议您将其发布在[codereview.se]上。 - Keppil
4
@Keppil和所有投票关闭的人:你们能指出帮助中心中具体违反了哪些条款吗?在我看来,这个问题符合定义范围。 - chiastic-security
2
@chiastic:我同意这并不是很清晰。当涉及到审查和改进工作代码时,[codereview.se]专门致力于此,因此我认为应该在那里提出问题。 - Keppil
4
@Keppil 我同意这个问题是 Code Review 的范围,但我并不认为这使它超出了这里的范围。有很多问题可以在多个地方合理地提问。SO 上有大量这样的问题,其中某人发布了一些“可工作”但效率低下的代码,并希望得到一些改进的线索,例如 http://stackoverflow.com/questions/25576302/wary-of-flattening-longish-liststring-into-string,对此没有人会反对。 - chiastic-security
显示剩余5条评论
2个回答

1
除非有明确告知,否则您不应假设总数适合于一个 int。尝试将 i 的类型更改为 long,甚至是 BigInteger,看看是否对您的分数产生影响。

您可以尝试使用 k 做同样的操作(并使用 Long.parseLong(line))。这将取决于问题的确切措辞,但也许单个值也超过了 int 的限制。

还有一件事...正如您所表达的那样,问题只是说您应该对所有整数求和。这留下了可能会有不是整数的行的可能性,在这种情况下,您应该跳过它们,而不是抛出一个 NumberFormatException(这是您的代码目前会做的)。

(而且您可能已经被告知每行只有一个条目...)

但是,如果您想挤出每一点性能,您需要将文件作为二进制文件而不是逐行读取:将每一行转换为String太昂贵了。如何执行此操作的详细说明可以在这个关于从文本文件中求和整数的问题中找到。


谢谢您的回答。我已经正确解决了这个问题,但问题在于它并不是很优化。完整的描述在这里:https://www.codeeval.com/open_challenges/24/ - Ivan T
你能发布完整的分析报告吗?它提供了多少细节? - chiastic-security
是的,你可以在这里找到它: max_memory = 20 * 1024 * 1024 # 20 MB max_time = 10 * 1000 # 10 秒

如果提交所需的时间超过了 10 秒或使用了超过 20MB 的内存,则得分为 0

if memory_taken > max_memory or time_taken > max_time: return 0max_total_score = total_max[category] memory_factor = 1 - memory_taken/max_memory time_factor = 1 - time_taken/max_time factor = (memory_factor + time_factor)/2 return score * max_total_score * factor / 100
- Ivan T
好的,我也添加了一个提高性能的建议。它基于整个程序都可以放入内存的假设。实际上这似乎有点学究:任何明智的编码人员都会像你一样编写代码。 - chiastic-security
2
@IvanT 我已经提出了这个新问题,希望能够更深入地回答你的问题,但同时也引发了一些新的问题:https://dev59.com/V-o6XIcBkEYKwwoYIAof - chiastic-security
你能否编辑你的答案,并在这里附上你的问题链接:https://dev59.com/V-o6XIcBkEYKwwoYIAof,我会接受它作为正确答案。 - Ivan T

1
我认为你的代码表现没有问题。也就是说,我不同意你的程序有任何问题的说法。
从文件或网络中读取数据比在内存中操作数据慢几个数量级。因此,将I/O与一些内存中数据操作混合的代码性能通常由用于I/O的时间所主导。对于内存中数据操作的微调很少值得做。如果I/O操作与数据操作并行发生(如果操作系统进行了一些预读取),那么数据操作几乎可以免费:使数据操作更快不会减少所需时间,因为数据操作的CPU时间的任何减少都将被等量抵消,而程序阻塞等待输入的时间则会增加。
需要良好性能的I/O程序必须减少它们花费在阻塞等待I/O上的时间。它们应该以一种使它们能够利用硬件和操作系统提供的优化来减少阻塞量的方式运行。
重要的是,在低层级别上,磁盘和网络并不在每个操作中使用少量字节。它们使用数据包或块的较大单位。与操作系统交互以读取少于一个磁盘块中存储的字节数是浪费的。程序通过缓冲其I/O来避免这样做,因此程序本身将许多小的I/O操作序列更改为更少但更大的操作。您正在使用BufferedReader,因此您已经在这样做了。
操作系统可能会进行一些预读取:如果您在文件开头请求块中的字节,则它会猜测您可能会按顺序读取文件,因此对于它也有意义去获取文件的一些后续块,以期望您的程序也需要它们。按顺序读取文件可以获得更好的性能。您已经在这样做了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接