我正在尝试使用多个线程拆分文本文件。该文件的大小为1 GB。我正在按字符读取文件。执行时间为24分54秒。他们可以减少执行时间的任何更好的方式,而不是按char读取文件。 我很难找到一种可以减少执行时间的方法。如果还有其他更好的方法来分割带有多个线程的文件,请也建议我。我对Java很陌生。
任何帮助将不胜感激。 :)
declare @tbl table(name varchar(20))
insert into @tbl values ('Abdul$Rahim')
insert into @tbl values('Tariq$Jameel')
select
PARSENAME(replace(name,'$','.'),2) as firstname,
PARSENAME(replace(name,'$','.'),1) as lastname
from @tbl
答案 0 :(得分:0)
最快的方法是将文件逐段映射到内存中(将一个大文件整体映射可能会导致不希望的副作用)。它将跳过一些相对昂贵的复制操作。操作系统会将文件加载到RAM中,而JRE会将其作为ByteBuffer
形式的堆外内存区域视图显示给您的应用程序。通常,您可以压缩性能的最后2倍/ 3倍。
内存映射方式需要大量的帮助程序代码(请参阅底部的片段),这并不总是最佳的战术方式。相反,如果您的输入是基于行的,并且您只需要合理的性能(现在可能没有),那么只需执行以下操作即可:
import java.nio.Files;
import java.nio.Paths;
...
File.lines(Paths.get("/path/to/the/file"), StandardCharsets.ISO_8859_1)
// .parallel() // parallel processing is still possible
.forEach(line -> { /* your code goes here */ });
为了对比,通过内存映射使用文件的代码的工作示例如下所示。对于固定大小的记录(当可以精确选择段以匹配记录边界时),可以并行处理后续段。
static ByteBuffer mapFileSegment(FileChannel fileChannel, long fileSize, long regionOffset, long segmentSize) throws IOException {
long regionSize = min(segmentSize, fileSize - regionOffset);
// small last region prevention
final long remainingSize = fileSize - (regionOffset + regionSize);
if (remainingSize < segmentSize / 2) {
regionSize += remainingSize;
}
return fileChannel.map(FileChannel.MapMode.READ_ONLY, regionOffset, regionSize);
}
...
final ToIntFunction<ByteBuffer> consumer = ...
try (FileChannel fileChannel = FileChannel.open(Paths.get("/path/to/file", StandardOpenOption.READ)) {
final long fileSize = fileChannel.size();
long regionOffset = 0;
while (regionOffset < fileSize) {
final ByteBuffer regionBuffer = mapFileSegment(fileChannel, fileSize, regionOffset, segmentSize);
while (regionBuffer.hasRemaining()) {
final int usedBytes = consumer.applyAsInt(regionBuffer);
if (usedBytes == 0)
break;
}
regionOffset += regionBuffer.position();
}
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}