我有一个包含以下形式的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中的速度是不可能的。是否有更快的实施,我只是没有看到?
答案 0 :(得分:1)
这个问题很有意思。如果你能提供更多信息会更好。
您缺少的一个重点是,您将在什么样的机器上实现这一目标?它有多少内存? CPU的速度有多快?多少个核心? I / O的速度有多快?
但无论如何,这里有一些可能有帮助的分析。如果你能提供更多信息,那么我们可以分析更多信息。
<强> 1.Memory 强>
(修改后,我在第一个回答中犯了一个错误。我没注意到你使用过ArrayList)
所以你使用的是ArrayList的HashMap。但这并不能保证内存开销。
假设Integer
和int
是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
。
<强>结论强>
总之,除非您分享您的环境和数据模式,否则很难提供真正的建议。优化通常基于特定情况,而不是一般情况。