Чтение сжатого файла gzip в java медленнее, чем чтение обычного файла?

#java #io

#java #io

Вопрос:

Я пытаюсь улучшить чтение файла в своем коде, поэтому я подумал сначала сделать микробеншмарк, интересный результат, который я наблюдал, показан ниже. Позвольте мне сначала объяснить каждый тест; который считывает файл с использованием кода:

 private void read(String source,Blackhole blackhole) throws  IOException {
   byte[] buffer = new byte[512];
   InputStream inputStream = new FileInputStream(source);
   int offset = 0,read = 0;
   while((read = inputStream.read(buffer,0,512))!=-1){
       blackhole.consume(buffer);
       offset =read;
   }
   System.out.println(offset/(1024*1024)   " MB read");
}
  

единственное различие в каждом бенчмарке — это исходный файл, который объясняется ниже:

 compress = gzip version of orignal file which has on disk size 181MB
normal = actual file of 2.0G
normalCompressSize = actual file truncated to size of compressed file i.e. 181MB
  

Результаты

 Benchmark                      Mode  Cnt  Score   Error  Units
FileReader.compress            avgt   20  5.722 ± 0.207   s/op
FileReader.normal              avgt   20  1.728 ± 0.010   s/op
FileReader.normalCompressSize  avgt   20  0.160 ± 0.004   s/op
  

Теперь я не могу найти причину, по которой сжатый файл читается с такой низкой скоростью. Я даже не использую GZIPInputStream для раздувания данных, но все равно это занимает так много времени по сравнению с другими, особенно с обработанным файлом того же размера.
Есть какая-либо конкретная причина, по которой это происходит?
Дайте мне знать, если я пропустил какую-либо важную деталь.

Отредактировано: Добавлен фрагмент для объяснения теста:

 public static void main(String[] args) throws IOException {
  Options opt = new OptionsBuilder()
    .include(".*"   FileReader.class.getSimpleName()   ".*")
    .jvmArgs("-server")
    .forks(1)
    .build();
  try {
    new Runner(opt).run();
  } catch (RunnerException e) {
   e.printStackTrace();
  }
}
  

Тесты:

 @Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.SECONDS)
public void compress(Blackhole blackhole) throws IOException {
  read("~/Documents/data.csv.gz",blackhole);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.SECONDS)
public void normalCompressSize(Blackhole blackhole) throws IOException   {
  read("~/Documents/data181MB.csv",blackhole);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.SECONDS)
public void normal(Blackhole blackhole) throws IOException {
  read("~/Documents/data.csv",blackhole);
}
  

Редактировать: обновлен код для байтов.
Конечные результаты

 Benchmark                      Mode  Cnt  Score   Error  Units
FileReader.compress            avgt   20  0.160 ± 0.005   s/op
FileReader.normal              avgt   20  1.818 ± 0.235   s/op
FileReader.normalCompressSize  avgt   20  0.150 ± 0.001   s/op
  

Комментарии:

1. вы измеряете циклы процессора, время настенных часов … или что?

2. Я использую JMH с этими аннотациями @Benchmark @BenchmarkMode (Режим. Среднее время) @OutputTimeUnit (временная единица. СЕКУНДЫ)

3. Чтение сжатого файла с помощью программы чтения не имеет особого смысла. Файл gzip не содержит символов.

4. Программа чтения не просто преобразует байты в символы. Он использует кодировку символов (Charset) для декодирования последовательностей байтов в символы. Это может быть очень просто для одних кодировок и более сложно для других. Например, UTF8 содержит символы, закодированные в 1, 2 или более байтах, и некоторые последовательности байтов недопустимы.

5. Вы измеряете время для преобразования сжатых двоичных данных в 16-разрядные символы Юникода, даже если это изначально не кодировка символов. Вы ничего не делаете правильно, поэтому время, которое требуется, не представляет интереса.