Вы все еще можете найти два байта:
public class CrLfProcessor implements ByteBufProcessor{
private byte previousByte;
@Override
public boolean process(byte value) {
if(previousByte == '\r'){
if(value == '\n'){
return false;
}
}
previousByte = value;
return true;
}
}
Вот JMH тест тестирования различных оптимизаций:
Fork(1)
@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Measurement(iterations = 10)
@Warmup(iterations = 10)
@BenchmarkMode(Mode.AverageTime)
public class ByteBufProcessorBenchmark {
private static interface ByteProcessor {
boolean process(byte value);
}
private static final int DATA_SIZE = 1024 * 1024;
private byte[] data;
@Setup(Level.Trial)
public void setUp() {
data = new byte[DATA_SIZE];
Random random = new Random();
random.nextBytes(data);
}
@Benchmark
public void crFirst(Blackhole blackhole) {
ByteProcessor byteProcessor = new ByteProcessor() {
private byte previousByte;
@Override
public boolean process(byte value) {
if(previousByte == '\r'){
if(value == '\n'){
return false;
}
}
previousByte = value;
return true;
}
};
doProcess(byteProcessor, blackhole);
}
@Benchmark
public void lfFirst(Blackhole blackhole) {
ByteProcessor byteProcessor = new ByteProcessor() {
private byte previousByte;
@Override
public boolean process(byte value) {
if (value == '\n') {
if(previousByte == '\r'){
return false;
}
}
previousByte = value;
return true;
}
};
doProcess(byteProcessor, blackhole);
}
@Benchmark
public void crFirstUpdateCacheOnDemand(Blackhole blackhole) {
ByteProcessor byteProcessor = new ByteProcessor() {
private byte previousByte;
@Override
public boolean process(byte value) {
if(previousByte == '\r'){
if(value == '\n'){
return false;
}
previousByte = 0;
}else if(value == '\r'){
previousByte = value;
}
return true;
}
};
doProcess(byteProcessor, blackhole);
}
@Benchmark
public void lfFirstUpdateCacheOnDemand(Blackhole blackhole) {
ByteProcessor byteProcessor = new ByteProcessor() {
private byte previousByte;
@Override
public boolean process(byte value) {
if (value == '\n') {
if(previousByte == '\r'){
return false;
}
previousByte = 0;
}else if(value == '\r'){
previousByte = value;
}
return true;
}
};
doProcess(byteProcessor, blackhole);
}
@Benchmark
public void consume(Blackhole blackhole){
for(int i = 0; i < data.length; i++){
blackhole.consume(data[i]);
}
}
private void doProcess(ByteProcessor byteProcessor, Blackhole blackhole){
for(int i = 0; i < data.length; i++){
blackhole.consume(byteProcessor.process(data[i]));
}
}
}
А вот повторно результаты:
# Run complete. Total time: 00:01:21
Benchmark Mode Cnt Score Error Units
ByteBufProcessorBenchmark.crFirst avgt 10 4,211 ± 0,061 ms/op
ByteBufProcessorBenchmark.crFirstUpdateCacheOnDemand avgt 10 4,285 ± 0,336 ms/op
ByteBufProcessorBenchmark.lfFirst avgt 10 4,375 ± 0,289 ms/op
ByteBufProcessorBenchmark.lfFirstUpdateCacheOnDemand avgt 10 4,129 ± 0,075 ms/op
ByteBufProcessorBenchmark.consume avgt 10 3,126 ± 0,152 ms/op
Как вы можете видеть самые быстрые опция ByteBufProcessorBenchmark.lfFirstUpdateCacheOnDemand
, но разница с ByteBufProcessorBenchmark.crFirst
заключается в том, что она не перевешивает добавленную сложность.
Каковы ваши требования к производительности, так как 4 мс (включая черную дыру, которую вы можете видеть по результатам, занимает 3 мс) на МБ ИМХО не замедляется вообще; В конце вы получаете 1 МБ за миллисекунду, что неплохо.
Я не могу повторно использовать процессор, и он все еще не достаточно быстрый. Но это лучше, чем у меня на данный момент. Благодаря! –
Вы можете его повторно использовать - просто добавьте метод с именем 'reset()', который устанавливает 'previousByte', чтобы сказать 0 и вызывать этот метод перед использованием процессора в другом буфере. Также вы можете проверить, будет ли разница в производительности (из-за эффектов кеша) путем замены двух операторов 'if'. –
Прохладный! Спасибо за информацию. Изменение этого не будет иметь никакого существенного влияния прямо сейчас, потому что у меня есть другие узкие места, которые нужно адресовать первым. Я добавлю примечание, чтобы изучить это в будущем. –