如何加快Java文本文件解析器的速度?

时间:2011-10-02 01:12:21

标签: java performance file parsing

我正在阅读大约600个文本文件,然后单独解析每个文件并将所有术语添加到地图中,这样我就可以知道600个文件中每个单词的频率。 (约400MB)。

我的解析器功能包括以下步骤(已订购):

  • 在两个标签之间查找文本,这是每个文件中要读取的相关文本。
  • 低调所有文字
  • string.split,带有多个分隔符。
  • 创建一个带有如下字样的arrayList:“aaa-aa”,然后添加到上面分割的字符串,并将“aaa”和“aa”折扣为String []。 (我这样做是因为我想要“ - ”作为分隔符,但我也希望“aaa-aa”只是一个单词,而不是“aaa”和“aa”。
  • 获取String []并映射到Map = new HashMap ...(word,frequency)
  • 打印所有内容。

在双核2.2GHz,2GB Ram中,我花了大约8分48秒。我想就如何加快这个过程提出建议。我应该期待这么慢吗?如果可能的话,我怎么知道(在netbeans中)哪些函数需要更多的时间来执行?

  找到独特的单词:398752。

CODE:

File file = new File(dir);
String[] files = file.list();

for (int i = 0; i < files.length; i++) {
    BufferedReader br = new BufferedReader(
        new InputStreamReader(
            new BufferedInputStream(
                new FileInputStream(dir + files[i])), encoding));
    try {
        String line;
        while ((line = br.readLine()) != null) {
            parsedString = parseString(line); // parse the string
            m = stringToMap(parsedString, m);
        }
    } finally {
        br.close();
    }
}

编辑:检查一下:

![在此处输入图片说明] [1]

我不知道该结束什么。


编辑:使用此功能的时间为80%

    public String [] parseString(String sentence){
         // separators; ,:;'"\/<>()[]*~^ºª+&%$ etc..
        String[] parts = sentence.toLowerCase().split("[,\\s\\-:\\?\\!\\«\\»\\'\\´\\`\\\"\\.\\\\\\/()<>*º;+&ª%\\[\\]~^]");

        Map<String, String> o = new HashMap<String, String>(); // save the hyphened words, aaa-bbb like Map<aaa,bbb>

        Pattern pattern = Pattern.compile("(?<![A-Za-zÁÉÍÓÚÀÃÂÊÎÔÛáéíóúàãâêîôû-])[A-Za-zÁÉÍÓÚÀÃÂÊÎÔÛáéíóúàãâêîôû]+-[A-Za-zÁÉÍÓÚÀÃÂÊÎÔÛáéíóúàãâêîôû]+(?![A-Za-z-])");
        Matcher matcher = pattern.matcher(sentence);

    // Find all matches like this: ("aaa-bb or bbb-cc") and put it to map to later add this words to the original map and discount the single words "aaa-aa" like "aaa" and "aa"
        for(int i=0; matcher.find(); i++){
           String [] tempo = matcher.group().split("-");
           o.put(tempo[0], tempo[1]);
        }
        //System.out.println("words: " + o);


        ArrayList temp = new ArrayList();
        temp.addAll(Arrays.asList(parts));

        for (Map.Entry<String, String> entry : o.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            temp.add(key+"-"+value);
            if(temp.indexOf(key)!=-1){
                temp.remove(temp.indexOf(key));
            }
            if(temp.indexOf(value)!=-1){
                temp.remove(temp.indexOf(value));
            }
        }


        String []strArray = new String[temp.size()];
        temp.toArray(strArray);
                return strArray;

  }

600个文件,每个文件大约0.5MB

EDIT3# - 每次读取一行时都不再编译该模式。新图片是:

enter image description here

2enter image description here

8 个答案:

答案 0 :(得分:3)

请确保使用-Xmx增加堆大小(如果尚未增加)。对于这个应用程序,影响可能是惊人的。

代码中可能影响最大的部分是执行次数最多的部分 - 这些部分是您未显示的部分。

内存屏幕截图

更新

查看屏幕截图中的所有Pattern $ 6对象。我认为你正在重新编译模式 - 可能是每一行。这将花费很多时间。

更新2 - 代码添加到问题后。

Yup - 在每一行编译的两种模式 - 明确的一种,以及分裂中的“ - ”(当然要便宜得多)。我希望他们没有将split()添加到String而不将编译模式作为参数。我看到其他一些可以改进的东西,但没有其他东西像大编译。只需在此函数外部编译模式一次,可以作为静态类成员。

答案 1 :(得分:1)

如果您还没有这样做,请使用BufferedInputStream和BufferedReader来读取文件。像这样的双缓冲比单独使用BufferedInputStream或BufferedReader要好得多。 E.g:

BufferedReader rdr = new BufferedReader(
    new InputStreamReader(
        new BufferedInputStream(
            new FileInputStream(aFile)
        )
        /* add an encoding arg here (e.g., ', "UTF-8"') if appropriate */
    )
);

如果您发布代码的相关部分,我们就有机会评论如何改进处理。

编辑:

根据您的修改,以下是一些建议:

  1. 编译模式一次并将其另存为静态变量,而不是每次调用parseString时编译。
  2. 首次调用时存储temp.indexOf(key)temp.indexOf(value)的值,然后使用存储的值,而不是第二次调用indexOf

答案 2 :(得分:1)

尝试使用具有匹配标记内每个单词的组的单个正则表达式 - 因此单个正则表达式可用于整个输入,并且不会有单独的“拆分”阶段。

否则你的方法似乎是合理的,虽然我不明白你的意思是“获取String [] ......” - 我以为你使用的是ArrayList。无论如何,尝试最小化对象的创建,包括建筑成本和垃圾收集成本。

答案 3 :(得分:1)

只是解析花了这么长时间,还是文件读取?

对于文件读取,您可以通过读取多个线程上的文件来加快速度。但第一步是弄清楚它是读书还是正在解析的解析,以便你能解决正确的问题。

答案 4 :(得分:1)

通过Netbeans探查器运行代码并找出它花费最多时间的位置(在项目上单击鼠标右键并选择配置文件,确保您没有时间记忆)。

答案 5 :(得分:1)

您向我们展示的代码中没有任何内容是性能问题的明显来源。问题可能与解析线条或提取单词并将其放入地图的方式有关。如果您需要更多建议,您需要发布这些方法的代码,以及声明/初始化地图的代码。

我的一般建议是分析应用程序并查看瓶颈所在,并使用该信息确定需要优化的内容。

@Ed Staub的建议也很合理。运行具有太小的堆的应用程序会导致严重的性能问题。

答案 6 :(得分:0)

看起来它大部分时间花在正则表达式上。我首先尝试编写代码而不使用正则表达式然后使用多个线程,就好像进程仍然看起来是CPU绑定的。

对于计数器,我会考虑使用TObjectIntHashMap来减少计数器的开销。我只使用一个地图,而不是创建一个字符串数组 - 然后我用它来构建另一个地图,这可能会浪费很多时间。

答案 7 :(得分:0)

预编译模式,而不是每次通过该方法编译它,并摆脱双缓冲:使用新的BufferedReader(新的FileReader(...))。