gpt4 book ai didi

文本文件解析器的 Java 字符串内存性能改进

转载 作者:行者123 更新时间:2023-12-03 02:24:25 25 4
gpt4 key购买 nike

我正在尝试在处理许多(数百万)字符串时优化内存使用情况。我正在阅读一个约 150 万行的文件,其中的列中包含十进制数字。例如,一个文件可能看起来像

16916576.643 4 -12312674.246 4        39.785 4  16916584.123 3  -5937726.325 3
36.794 3
16399226.418 6 -4129008.232 6 43.280 6 16399225.374 4 -1891751.787 4
39.885 4
12415561.671 9 -33057782.339 9 52.412 9 12415567.518 8 -25595925.487 8
49.950 8
15523362.628 5 -12597312.619 5 40.579 5 15523369.553 5 -9739990.371 5
42.003 5
12369614.129 8 -28797729.913 8 50.068 8 0.000 0.000
0.000
....

目前我正在使用 String.split("\\s+") 来分隔这些数字,然后对每个部分调用 Double.parseDouble() String[] 的,看起来像:

String[] data = line.split("\\s+");
double firstValue = Double.parseDouble(data[0]);
double secondValue = Double.parseDouble(data[1]);
double thirdValue = Double.parseDouble(data[2]);

这最终会创建很多 String 对象。我还可能在行的开头或结尾有空格,因此我必须在分割行之前调用 trim() ,这也会创建另一个 String 对象。垃圾收集器会处理这些 String 对象,这会导致速度变慢。 Java 中是否有更高效的内存结构来做到这一点?我正在考虑使用 char[] 而不是 String 但我不确定这样做是否会有实质性的改进。

最佳答案

如果您确实这是一个严重瓶颈,您始终可以将字符串直接解析为Double

// Keep track of my state.
private static class AsDoublesState {

// null means no number waiting for add.
Double d = null;
// null means not seen '.' yet.
Double div = null;
// Is it negative.
boolean neg = false;

void consume(List<Double> doubles, char ch) {
// Digit?
if ('0' <= ch && ch <= '9') {
double v = ch - '0';
if (d == null) {
d = v;
} else {
d = d * 10 + v;
}
// Count digits after the dot.
if (div != null) {
div *= 10;
}
} else if (ch == '.') {
// Decimal point - start tracking how much to divide by.
div = 1.0;
} else if (ch == '-') {
// Negate!
neg = true;
} else {
// Everything else completes the number.
if (d != null) {
if (neg) {
d = -d;
}
if (div != null) {
doubles.add(d / div);
} else {
doubles.add(d);
}
// Clear down.
d = null;
div = null;
neg = false;
}
}
}
}

private static List<Double> asDoubles(String s) {
// Grow the list.
List<Double> doubles = new ArrayList<>();
// Track my state.
AsDoublesState state = new AsDoublesState();

for (int i = 0; i < s.length(); i++) {
state.consume(doubles, s.charAt(i));
}
// Pretend a space on the end to flush an remaining number.
state.consume(doubles, ' ');
return doubles;
}

public void test() {
String s = "16916576.643 4 -12312674.246 4 39.785 4 16916584.123 3 -5937726.325 3 36.794 3";
List<Double> doubles = asDoubles(s);
System.out.println(doubles);
}

如果给出错误的数据,这将严重破坏。例如。 123--56...392.86 对于它来说是一个完全有效的数字,6.0221413e+23 将是两个数字。

这里有一个改进的 State,使用 AtomicDouble 来避免创建所有这些 Double 对象。

// Keep track of my state.
private static class AsDoublesState {

// Mutable double value.
AtomicDouble d = new AtomicDouble();
// Mutable double value.
AtomicDouble div = new AtomicDouble();
// Is there a number.
boolean number = false;
// Is it negative.
boolean negative = false;

void consume(List<Double> doubles, char ch) {
// Digit?
if ('0' <= ch && ch <= '9') {
double v = ch - '0';
d.set(d.get() * 10 + v);
number = true;
// Count digits after the dot.
div.set(div.get() * 10);
} else if (ch == '.') {
// Decimal point - start tracking how much to divide by.
div.set(1.0);
} else if (ch == '-') {
// Negate!
negative = true;
} else {
// Everything else completes the number.
if (number) {
double v = d.get();
if (negative) {
v = -v;
}
if (div.get() != 0) {
v = v / div.get();
}
doubles.add(v);
// Clear down.
d.set(0);
div.set(0);
number = false;
negative = false;
}
}
}
}

关于文本文件解析器的 Java 字符串内存性能改进,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31591659/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com