使用TLongObjectHashMap非常慢

时间:2015-01-06 10:43:47

标签: java dictionary

我需要在HashMap中输入大约2000万个条目。我根据Why is Java HashMap slowing down?

选择了TLongObjectHashMap

代码如下:

StringBuilder sb = new StringBuilder("");
StringBuilder value = new StringBuilder("");
TLongObjectHashMap<String> map = new TLongObjectHashMap<String>();

in = new FileInputStream(new File(inputFile));
br = new BufferedReader(new InputStreamReader(in), 102400);
for (String inLine; (inLine = br.readLine()) != null;) {
    sb.setLength(0);
    for (i = 0; i < 2; i++) {
                for (j = 1; j < 12; j++) {
                    sb.append(record.charAt(j));
                }
            }

            for (k = 2; k < 4; k++) {
                value.append(record.charAt(k));
            }
            for (k = 7; k < 11; k++) {
                value.append(record.charAt(k));
            }
    map.put(Long.parseLong(sb.toString()), value.toString());
    value.delete(0, value.length());
}

我使用了GNU Trove。尽管如此,变得极其缓慢,几乎停止在大约1500万条目。还没有OutOfMemoryError。有什么问题?

我没有选择使用DB。

注意:在此循环之前计算诸如1,12,2,4等的值并将其存储在变量中,而变量将在此处使用。我现在用一些值替换它们

2 个答案:

答案 0 :(得分:4)

  

我使用了GNU Trove。尽管如此,变得极其缓慢,几乎停止在大约1500万条目。还没有OutOfMemoryError。有什么问题?

问题是你做了假设而不是验证它们。

您还没有分析您的代码。您的真实的代码,而不是您在此处发布的半编辑内容(提示:当变量名称不匹配时,很明显它是&#39 ;不是真正的代码。)

是的,您正在编写效率低下的代码。那些用于复制字符的循环,例如,重复String.substring()。你已经被告知了。但它被埋没在大量评论中,你可能错过了它。另一个好的评论是使用这些子串的简单连接,而不是使用StringBuilder

但真正的问题是假设您的地图效率低下,基于您在互联网上阅读的内容,并且没有采取任何措施来挑战该假设。我可以保证从磁盘读取记录所花费的时间远远大于在每个记录的地图中插入一个值的时间。

你需要做的就是向自己证明这一点。分析代码是执行此操作的最佳方法,但您也可以分离出程序的各个部分。使用如下所示的简单循环来了解地图的实际速度(我使用HashMap因为我没有安装Trove库;大约需要2分钟才能填充地图100,000,000项)。我会留给你写一个类似的测试来读取你文件中的数据。

private static Map<Long,String> fillMap(int items)
{
    Map<Long,String> map = new HashMap<Long,String>(items);
    Random rnd = new Random();

    long start = System.currentTimeMillis();

    for (int ii = 0 ; ii < items ; ii++)
    {
        map.put(new Long(rnd.nextLong()), new String("123456789012345678901234567890"));
    }

    long finish = System.currentTimeMillis();
    double elapsed = ((finish - start) / 1000.0);
    System.out.format("time to produce %d items: %8.3f seconds (map size = %d)\n", items, elapsed, map.size());
    return map;
}

答案 1 :(得分:0)

我不相信JDK内置的HashMap无法处理这个问题。我看到有两个问题

  • 地图在不断增长时不断重播
  • 非必要的字符串构建器对象

当底层存储阵列负载系数达到75%时,会发生重新发送

DEFAULT_INITIAL_CAPACITY = 16;  
DEFAULT_LOAD_FACTOR = 0.75;  
THRESHOLD = DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR;

我认为以下是指数减少的工作,并做同样的

double expected_maximal_number_of_data = 30000000d;
int capacity = (int) ((expected_maximal_number_of_data)/0.75+1);
HashMap<Long, String> map = new HashMap<Long, String>(capacity);
for (String inLine; (inLine = br.readLine()) != null;) {
    Long key = Long.parseLong(record.substring(1, 12));
    String value = record.substring(2, 4) + record.substring(7, 11);
    map.put(key, value);
}

如果您的计算机有2GB内存,那么您应该没有问题,估计完成时间<16秒。

相关问题