我正在使用Files.lines()从大文件(8GB +)中读取行。如果按顺序处理,它的工作效果非常好,内存占用非常少。一旦我将parallel()添加到流中,它似乎就会挂起它正在处理的数据,最终导致内存不足异常。我相信这是Spliterator在尝试拆分时缓存数据的结果,但我不确定。我唯一的想法是使用trySplit方法编写自定义Spliterator,剥离少量数据以进行拆分,而不是尝试将文件拆分一半或更多。还有其他人遇到过这个吗?
答案 0 :(得分:3)
跟踪代码我的猜测是Spliterator
使用的Files.lines()
是Spliterators.IteratorSpliterator
。其trySplit()
方法有此评论:
/*
* Split into arrays of arithmetically increasing batch
* sizes. This will only improve parallel performance if
* per-element Consumer actions are more costly than
* transferring them into an array. The use of an
* arithmetic progression in split sizes provides overhead
* vs parallelism bounds that do not particularly favor or
* penalize cases of lightweight vs heavyweight element
* operations, across combinations of #elements vs #cores,
* whether or not either are known. We generate
* O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
* potential speedup.
*/
然后,代码看起来像是分成1024个记录(行)的多个批次。因此,第一次拆分将读取1024行,然后下一行将读取2048行等等。每个拆分将读取越来越大的批量。
如果您的文件非常大,最终将达到最大批量大小33,554,432,即1<<25
。请记住,这些行不是字节,这可能会导致内存不足错误,尤其是当您开始让多个线程读取那么多时。
这也解释了减速。在线程处理这些行之前,会提前读取这些行。
所以我要么根本不使用parallel()
,要么你必须因为你所做的计算每行都很昂贵,所以编写你自己的Spliterator并不会像这样分裂。可能只是总是使用1024批次就好了。
答案 1 :(得分:0)