在Java中增加Map值的最有效的方法 [英] Most efficient way to increment a Map value in Java

查看:377
本文介绍了在Java中增加Map值的最有效的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望这个问题对于这个论坛来说不是太基础,但我们会看到。我想知道如何重构一些代码,以获得更好的性能,是运行一次。

I hope this question is not considered too basic for this forum, but we'll see. I'm wondering how to refactor some code for better performance that is getting run a bunch of times.

说我创建一个字频率列表,使用一个Map可能是一个HashMap),其中每个键是一个字符串与被计数的字,该值是一个Integer,每当该字的标记被找到时递增。

Say I'm creating a word frequency list, using a Map (probably a HashMap), where each key is a String with the word that's being counted and the value is an Integer that's incremented each time a token of the word is found.

在Perl中,增加这样的值将非常容易:

In Perl, incrementing such a value would be trivially easy:

$map{$word}++;

但在Java中,它要复杂得多。这里我现在的方式:

But in Java, it's much more complicated. Here the way I'm currently doing it:

int count = map.containsKey(word) ? map.get(word) : 0;
map.put(word, count + 1);

当然依赖于较新的Java版本中的自动装箱功能。我不知道你是否可以建议一个更有效的方式增加这样的价值。有没有甚至良好的性能原因避开集合框架和使用其他的东西?

Which of course relies on the autoboxing feature in the newer Java versions. I wonder if you can suggest a more efficient way of incrementing such a value. Are there even good performance reasons for eschewing the Collections framework and using a something else instead?

更新:我做了几个答案的测试。见下文。

Update: I've done a test of several of the answers. See below.

推荐答案

一些测试结果



很多好的答案这个问题 - 感谢人们 - 所以我决定运行一些测试,弄清楚哪个方法实际上是最快的。我测试的五种方法是这些:

Some test results

I've gotten a lot of good answers to this question--thanks folks--so I decided to run some tests and figure out which method is actually fastest. The five methods I tested are these:


  • 我在问题

  • 建议使用TestForNull作者:Aleksandar Dimitrov

  • Hank Gay建议的AtomicLong方法

  • jrudolph建议的Trove方法

  • phax.myopenid.com建议的「MutableInt」方法

  • the "ContainsKey" method that I presented in the question
  • the "TestForNull" method suggested by Aleksandar Dimitrov
  • the "AtomicLong" method suggested by Hank Gay
  • the "Trove" method suggested by jrudolph
  • the "MutableInt" method suggested by phax.myopenid.com

这是我做的...


  1. 创建了五个相同的类,除了下面显示的差异。每个类都必须执行我所提供的场景的典型操作:打开一个10MB的文件并读入,然后执行文件中所有单词令牌的频率计数。因为这平均只有3秒,所以我执行频率计数(而不是I / O)10次。

  2. 定时了10次迭代的循环,但不是I / O操作,并记录所花费的总时间(以秒钟为单位),基本上使用 Ian Darwin在Java Cookbook中的方法

  3. 执行了所有五个测试,

  1. created five classes that were identical except for the differences shown below. Each class had to perform an operation typical of the scenario I presented: opening a 10MB file and reading it in, then performing a frequency count of all the word tokens in the file. Since this took an average of only 3 seconds, I had it perform the frequency count (not the I/O) 10 times.
  2. timed the loop of 10 iterations but not the I/O operation and recorded the total time taken (in clock seconds) essentially using Ian Darwin's method in the Java Cookbook.
  3. performed all five tests in series, and then did this another three times.
  4. averaged the four results for each method.



结果



我将首先展示结果,然后为感兴趣的人显示以下代码。

Results

I'll present the results first and the code below for those who are interested.

ContainsKey 方法是最慢的,所以我将给出每个方法的速度与该方法的速度相比。

The ContainsKey method was, as expected, the slowest, so I'll give the speed of each method in comparison to the speed of that method.


  • ContainsKey: 30.654秒(基线)

  • AtomicLong: 29.780秒li>
  • TestForNull: 28.804秒(快1.06倍)

  • Trove: 26.313秒

  • MutableInt: 25.747秒(速度的1.19倍)

  • ContainsKey: 30.654 seconds (baseline)
  • AtomicLong: 29.780 seconds (1.03 times as fast)
  • TestForNull: 28.804 seconds (1.06 times as fast)
  • Trove: 26.313 seconds (1.16 times as fast)
  • MutableInt: 25.747 seconds (1.19 times as fast)

看起来只有MutableInt方法和Trove方法明显更快,因为只有它们的性能提升超过10% 。然而,如果线程是一个问题,AtomicLong可能比其他人更有吸引力(我不是真的确定)。我也跑了TestForNull与最终变量,但差别是可以忽略不计。

It would appear that only the MutableInt method and the Trove method are significantly faster, in that only they give a performance boost of more than 10%. However, if threading is an issue, AtomicLong might be more attractive than the others (I'm not really sure). I also ran TestForNull with final variables, but the difference was negligible.

注意,我没有profiled记忆用法在不同的场景。我很高兴听到任何人谁有良好的见解如何MutableInt和Trove方法可能会影响内存使用。

Note that I haven't profiled memory usage in the different scenarios. I'd be happy to hear from anybody who has good insights into how the MutableInt and Trove methods would be likely to affect memory usage.

我个人,我发现MutableInt方法最有吸引力,因为它不需要加载任何第三方类。因此,除非我发现它的问题,这是我最有可能去的方式。

Personally, I find the MutableInt method the most attractive, since it doesn't require loading any third-party classes. So unless I discover problems with it, that's the way I'm most likely to go.

import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
int count = freq.containsKey(word) ? freq.get(word) : 0;
freq.put(word, count + 1);



TestForNull



TestForNull

import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
Integer count = freq.get(word);
if (count == null) {
    freq.put(word, 1);
}
else {
    freq.put(word, count + 1);
}



AtomicLong



AtomicLong

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
...
final ConcurrentMap<String, AtomicLong> map = 
    new ConcurrentHashMap<String, AtomicLong>();
...
map.putIfAbsent(word, new AtomicLong(0));
map.get(word).incrementAndGet();



Trove



Trove

import gnu.trove.TObjectIntHashMap;
...
TObjectIntHashMap<String> freq = new TObjectIntHashMap<String>();
...
freq.adjustOrPutValue(word, 1, 1);



MutableInt



MutableInt

import java.util.HashMap;
import java.util.Map;
...
class MutableInt {
  int value = 1; // note that we start at 1 since we're counting
  public void increment () { ++value;      }
  public int  get ()       { return value; }
}
...
Map<String, MutableInt> freq = new HashMap<String, MutableInt>();
...
MutableInt count = freq.get(word);
if (count == null) {
    freq.put(word, new MutableInt());
}
else {
    count.increment();
}

这篇关于在Java中增加Map值的最有效的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆