我有一段代码如下:
while ((line = reader.readNext()) != null) {
identityJmPojo.setIdentity(line[0]);
identityJmPojo.setJM(line.length > 1 ? line[1] : jsonValue);
identityJmList.add(identityJmPojo);
size = identityJmList.size();
switch (size) {
case STEP:
counter = counter + STEP;
payloadEngine.prepareJson(identityJmList, uploaderPoolService);
identityJmList.clear();
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
logger.info("=================== Time taken to read " + STEP + " records from CSV: " + elapsedTime + " and total records read: " + counter + "===================");
break;
}
}
我正在从CSV中读取数千亿条记录,速度对业务至关重要。
现在声明:
identityJmPojo.setJM(line.length > 1 ? line[1] : jsonValue);
业务定义的考虑因素是line.length是否>在第一次迭代中,对于第n次迭代,它将是相同的,因此我想在每次循环迭代中删除冗余条件检查。只是以某种方式设置这一次,再也不使用三元运算符。
任何提示或头脑都会非常感激。
答案 0 :(得分:2)
首先我应该注意,除非setJM()
方法特别昂贵,否则这看起来不是优化的有力候选者。在分析器中运行您的代码,找出它真正花费时间的地方,然后再决定是否适合您的工作。
只猜测你正在做的处理类型 - 但如果瓶颈是磁盘IO,我不会感到惊讶。时间cat inputfile > /dev/null
- 这将让您了解简单地从磁盘上获取字节所需的时间(但要小心解释这一点,因为文件系统内存缓存会使问题混淆)。同样,最简单的程序生成模拟输出数据,写入磁盘。
两个非常简单的选项,它们非常明显:
在您进入循环之前处理第一行:
line = reader.readNext();
if(line != null) {
stuffToDoOnlyOnFirstLine(...);
}
while(line != null) {
stuffToDoOnAllLines(...);
line = reader.readNext();
}
拥有两个reader.readNext()
可能会感觉很狡猾,但这是一个完善的模式,称为“预读,直读”。
标记表示作业已完成
boolean processedFirstLine = false;
while(...) {
...
if(!processedFirstLine) {
stuffToDoOnFirstLine(...);
lineLengthNoted = true;
}
...
}
通过将功能放入类中,您可以获得更多的OO:
class OnceOnlyThingDoer {
private boolean done = false;
public OnceOnlyThingDoer(...) {
// set member variables e.g. the target POJO
}
public void record(int[] line) {
if(!done) {
doTheThing(line); // e.g. call your method on the target POJO
done = true;
}
}
}
你可以使用lambdas做类似的整洁事情,但我想如果你对lambdas感到满意,你就不会问这个问题。
@Test
public void writesOnlyOnce() {
List<Integer> output = new ArrayList<>();
Consumer<Supplier<Integer>> consumer = consumeOnlyOnce(num -> output.add(num));
consumer.accept(() -> 5); // body of supplier could be much more complex
consumer.accept(() -> 3);
assertThat(output, is(Collections.singletonList(5)));
}
public Consumer<Supplier<Integer>> consumeOnlyOnce(Consumer<Integer> handler) {
final boolean[] done = new boolean[] { false };
return supplier -> {
if (!done[0]) {
handler.accept(supplier.get());
}
done[0] = true;
};
}
这里的关键是我们传递Supplier
函数。它的主体可能很复杂且运行起来很昂贵,但它只在supplier.get()
被调用时运行,由done
保护。不幸的是,在Java中我们不能在lambda中使用非最终的超出范围的变量,所以为了跟踪状态我们需要使用可变的东西,因此是单元素int[]
数组。
答案 1 :(得分:-1)
你可以使用do - while循环:
line = reader.readNext();
boolean useLine = line.length > 1;
do {
identityJmPojo.setIdentity(line[0]);
identityJmPojo.setJM(useLine ? line[1] : jsonValue);
....
line = reader.readNext();
} while(line != null);