执行速度很慢

时间:2012-05-22 18:14:45

标签: java string file hashmap

我有一个基本的方法,它从硬盘驱动器中读取大约1000行,每行约10,000行。另外,我有一个名为String的{​​{1}}数组,其中包含用户的所有“描述词”。我创建了一个HashMap,其数据结构为userDescription,对应HashMap<String, HashMap<String, Integer>>

该文件组织为: HashMap<eachUserDescriptionWords, HashMap<TweetWord, Tweet_Word_Frequency>>

我的方法是:

<User=A>\t<Tweet="tweet...">\n
<User=A>\t<Tweet="tweet2...">\n
<User=B>\t<Tweet="tweet3...">\n
....

此处,方法for (File file : tweetList) { if (file.getName().endsWith(".txt")) { System.out.println(file.getName()); BufferedReader in; try { in = new BufferedReader(new FileReader(file)); String str; while ((str = in.readLine()) != null) { // String split[] = str.split("\t"); String split[] = ptnTab.split(str); String user = ptnEquals.split(split[1])[1]; String tweet = ptnEquals.split(split[2])[1]; // String user = split[1].split("=")[1]; // String tweet = split[2].split("=")[1]; if (tweet.length() == 0) continue; if (!prevUser.equals(user)) { description = userDescription.get(user); if (description == null) continue; if (prevUser.length() > 0 && wordsCount.size() > 0) { for (String profileWord : description) { if (wordsCorr.containsKey(profileWord)) { HashMap<String, Integer> temp = wordsCorr .get(profileWord); wordsCorr.put(profileWord, addValues(wordsCount, temp)); } else { wordsCorr.put(profileWord, wordsCount); } } } // wordsCount = new HashMap<String, Integer>(); wordsCount.clear(); } setTweetWordCount(wordsCount, tweet); prevUser = user; } } catch (IOException e) { System.err.println("Something went wrong: " + e.getMessage()); } } } 计算单个用户的所有推文的单词频率。方法是:

setTweetWord

方法addValues检查private void setTweetWordCount(HashMap<String, Integer> wordsCount, String tweet) { ArrayList<String> currTweet = new ArrayList<String>( Arrays.asList(removeUnwantedStrings(tweet))); if (currTweet.size() == 0) return; for (String word : currTweet) { try { if (word.equals("") || word.equals(null)) continue; } catch (NullPointerException e) { continue; } Integer countWord = wordsCount.get(word); wordsCount.put(word, (countWord == null) ? 1 : countWord + 1); } } 是否包含已存在于巨型HashMap wordsCorr中的单词。如果是,则会增加原始HashMap wordCount中单词的计数。

现在,我的问题是无论我做什么,程序都非常慢。我在我的服务器上运行了这个版本,它有相当不错的硬件但是它已经28小时了,扫描的文件数量只有~450。我试着看看我是否反复做了一些可能没必要的事,我纠正了其中的一些。但程序仍然很慢。

另外,我已经将堆大小增加到1500米,这是我可以达到的最大值。

有什么我可能做错了吗?

感谢您的帮助!

编辑:分析结果 首先,我真的要感谢你们的评论。我已经改变了程序中的一些东西。我现在已经预编译了正则表达式而不是直接wordsCorr和其他优化。但是,在分析后,我的String.split()方法花费的时间最长。所以,这是addValues的代码。有什么我应该优化的吗?哦,我也改变了我的addValues方法。

startProcess

EDIT2:即使在尝试使用它之后,该程序也没有按预期运行。我完成了“慢速方法” private HashMap<String, Integer> addValues( HashMap<String, Integer> wordsCount, HashMap<String, Integer> temp) { HashMap<String, Integer> merged = new HashMap<String, Integer>(); for (String x : wordsCount.keySet()) { Integer y = temp.get(x); if (y == null) { merged.put(x, wordsCount.get(x)); } else { merged.put(x, wordsCount.get(x) + y); } } for (String x : temp.keySet()) { if (merged.get(x) == null) { merged.put(x, temp.get(x)); } } return merged; } 的所有优化,但它没有用。所以我开始创建单词字典并首先为每个单词分配索引,然后进行处理。让我们看看它去哪里。谢谢你的帮助!

6 个答案:

答案 0 :(得分:2)

我想到了两件事:

  • 您正在使用String.split(),它使用正则表达式进行拆分。那是完全超大的。请改用Apache StringUtils中的许多splitXYZ()方法之一。
  • 您可能正在创建非常大的哈希映射。当具有非常大的散列映射时,散列冲突将使散列映射函数慢得多。这可以通过使用更广泛传播的哈希值来改进。请参阅此处的示例:Java HashMap performance optimization / alternative

答案 1 :(得分:1)

一个建议(我不知道你会从中获得多少改进)是基于curTweet永远不会被修改的观察。无需创建副本。即。

ArrayList<String> currTweet = new ArrayList<String>(
            Arrays.asList(removeUnwantedStrings(tweet)));

可以替换为

List<String> currTweet = Arrays.asList(removeUnwantedStrings(tweet));

或者您可以直接使用数组(速度稍快)。即。

String[] currTweet = removeUnwantedStrings(tweet);

此外,

word.equals(null)
根据{{​​1}}合同的定义,

总是false。正确的无效检查方法是:

equals

此外,如果执行此操作,则不需要null-pointer-exception try-catch。异常处理在发生时很昂贵,因此如果你的单词数组往往会返回大量的空值,这可能会减慢代码的速度。

更一般地说,这是您应该分析代码并找出实际瓶颈在哪里(如果存在瓶颈)而不是寻找优化广告的情况之一特别

答案 2 :(得分:1)

您可以从更多优化中获益:

  • String.split每次都会将输入正则表达式(以字符串形式)重新编译为模式。您应该有一个static final Pattern ptnTab = Pattern.compile( "\\t" ), ptnEquals = Pattern.compile( "=" );并致电,例如ptnTab.split( str )。结果表现应该接近StringTokenizer。
  • word.equals( "" ) || word.equals( null )。这里有很多浪费的周期。如果你实际上看到空单词,那么你正在捕捉NPE,这是非常昂贵的。请参阅上面@trutheality的回复。
  • 您应该为HashMap分配一个非常大的初始容量,以避免必然会发生的所有大小调整。

答案 3 :(得分:0)

split()使用正则表达式,它们不是“快”。尝试使用StringTokenizer或其他东西。

答案 4 :(得分:0)

您是否考虑过使用db而不是Java。使用数据库工具,您可以使用表中数据库附带的数据加载工具加载数据,然后可以从中进行设置处理。我看到的一个挑战是在表格中加载数据,因为字段不是用“'”或“:”这样的常见分隔符分隔的。

答案 5 :(得分:0)

您可以像这样重写addValues以加快速度 - 一些注意事项:

  • 我没有测试过代码,但我认为它与你的代码相同。
  • 我没有测试它是否更快(但如果不是这样会感到惊讶)
  • 我假设wordsCount大于temp,如果没有在代码中交换它们
  • 我还用HashMap替换了所有Map s,这对你没有任何影响,但稍后会让代码更容易更改

private Map<String, Integer> addValues(Map<String, Integer> wordsCount, Map<String, Integer> temp) {

    Map<String, Integer> merged = new HashMap<String, Integer>(wordsCount); //puts everyting in wordCounts

    for (Map.Entry<String, Integer> e : temp.entrySet()) {
        Integer countInWords = merged.get(e.getKey()); //the number in wordsCount
        Integer countInTemp = e.getValue();
        int newCount = countInTemp + (countInWords == null ? 0 : countInWords); //the sum
        merged.put(e.getKey(), newCount);
    }
    return merged;
}