Java:从文本文件中读取大约2亿个边缘到内存的最快方法?

时间:2016-04-13 00:14:37

标签: java

我有一个包含以下形式的2亿条边的文本文件:

12 34
12 920

指示从节点12到节点34的边缘。它们需要以这样的方式存储在存储器中,以便能够容易地访问相邻边缘列表,以便快速查找连接到的每个边缘。一个给定的顶点。

我使用HashMap存储节点,每个节点只包含一个链接列表:

public class Node {
    List<Node> links;

    public synchronized void AddLink(Node node)
    {
        if (links.indexOf(node) == -1)
            links.add(node);
    }
}

我还使用BufferedReader.readLine()从文本文件中读取每一行。问题是,这种方法需要大约85秒来读取所有2亿个边缘。

30个小时后,我现在倾向于相信Java中的速度是不可能的。是否有更快的实施,我只是没有看到?

1 个答案:

答案 0 :(得分:1)

这个问题很有意思。如果你能提供更多信息会更好。

您缺少的一个重点是,您将在什么样的机器上实现这一目标?它有多少内存? CPU的速度有多快?多少个核心? I / O的速度有多快?

但无论如何,这里有一些可能有帮助的分析。如果你能提供更多信息,那么我们可以分析更多信息。

<强> 1.Memory

(修改后,我在第一个回答中犯了一个错误。我没注意到你使用过ArrayList)

所以你使用的是ArrayList的HashMap。但这并不能保证内存开销。

假设Integerint是4个字节,引用是8个字节(我很可能在这里错了,只是把它当作一个指针)。

在最好的情况下,假设只有一个顶点链接到所有其他顶点,并且此顶点是文件中的第一个数字。然后内存将是200M * 8字节= 1.6 GB。

但在最坏的情况下,仍有一个顶点链接到其他顶点,但现在这个顶点是文件中的第二个数字。然后内存将是200M * 20字节= 4 GB。

最糟糕的情况是,在浏览了Java HashMap的source code之后,HashMap的每个节点/条目都包含这些字段。

final int hash;
final K key;
V value;
Node<K,V> next;`

2.数据结构

就像其他人已经说过的那样,你需要关心数据结构。 HashMap在这里可能适合也可能不适合。

事先知道所有顶点吗?例如,所有顶点都是0到20K。在这种情况下,我不会在给定这个大型数据集的情况下使用HashMap。相反,我会使用列表列表,它会将每个节点的内存从20个字节显着减少到仅4个字节。所以我只需要800MB内存!

但是,如果顶点遍布整数空间,则此方法不可行。但是,您仍然可能无法正确使用数据结构。你有足够的容量初始化HashMap吗?当HashMap相对满时,它必须rehash,这是非常耗费成本的。同样,你是否用足够的容量初始化ArrayList?当ArrayList已满时,它必须为resize,这也是成本计算的。

最后,我注意到你使用了SynchronizedMap,这在你的情况下真的很糟糕。 SynchronizedMap只不过是HashMap的互斥锁,它会在多个线程同时修改HashMap时锁定整个HashMap,这意味着代码中没有并行性。相反,您应该使用ConcurrentHashMap,其粒度明显小于SynchronizedMap。直观的解释是,它只锁定它正在修改的链表,所以现在如果多个线程修改了不同的链表,那么它们可以并行执行此操作。

3.阅读方法

要读取此大文件,您可能需要签出readLine以外的方法。其他人已在FileChannel包中指出nio。结帐MappedByteBuffer

<强>结论

总之,除非您分享您的环境和数据模式,否则很难提供真正的建议。优化通常基于特定情况,而不是一般情况。