2015-11-20 2 views
3

Мне нужно извлечь файл из облачной хранилища Google, скомпилировать его, а затем проанализировать с помощью Wire в объект proto-buf.Неожиданная огромная разница в скорости ввода-вывода между двумя методами

Сначала я попытался сделать следующее:

final GcsInputChannel inputChannel; 
final ByteArrayInputStream byteArrayInputStream; 
final GZIPInputStream compressedData; 

final MusicList musicList; 

logger.info("Receiving the object"); 
inputChannel = gcsService.openReadChannel(gcsFilename, 0); 

final int fileSize = (int) gcsService.getMetadata(gcsFilename).getLength(); 
final ByteBuffer result = ByteBuffer.allocate(fileSize); 
inputChannel.read(result); 

byteArrayInputStream = new ByteArrayInputStream(result.array()); 
compressedData = new GZIPInputStream(byteArrayInputStream); 
musicList = new Wire(MusicList.class).parseFrom(compressedData, MusicList.class); 
closeQuietly(byteArrayInputStream, inputChannel, compressedData); 

В основном это в первую очередь выбирает весь файл в буфер байт, а затем передает его в ООН-компрессора. Я подумал, почему бы не амортизировать время, затрачиваемое на передачу фактического входного потока в UN-компрессор.

final GcsInputChannel inputChannel = gcsService.openPrefetchingReadChannel(gcsFilename, 0, 1024 * 1024); 
final InputStream download = Channels.newInputStream(inputChannel); 
final GZIPInputStream compressedData; 

final MusicList musicList; 

logger.info("Receiving the object"); 
compressedData = new GZIPInputStream(download); 
musicList = new Wire(MusicList.class).parseFrom(compressedData, MusicList.class); 
closeQuietly(download, inputChannel, compressedData); 

Удивительно, но первый метод работает почти в 6 раз быстрее, чем второй. Ясность по этому вопросу очень ценится.

----- EDIT -----

Размер файла не более чем мега байт.

ответ

1

Буферизация - это ключ здесь. Оформление входного потока по умолчанию, возвращаемого каналами. Новый поток ввода с буферизированным входным потоком дает самый быстрый способ выполнить задание.

Вот окончательный код

final GcsInputChannel inputChannel; 
final BufferedInputStream bufferedInputStream; 
final GZIPInputStream compressedData; 
final InputStream inputStream; 

final MusicList musicList; 

logger.info("Receiving the object"); 
try { 

    inputChannel = gcsService.openReadChannel(gcsFilename, 0); 
    bufferedInputStream = new BufferedInputStream(inputStream = Channels.newInputStream(inputChannel)); 
    compressedData = new GZIPInputStream(bufferedInputStream); 
    musicList = new Wire(MusicList.class).parseFrom(compressedData, MusicList.class); 
} catch (IOException e) { 
    e.printStackTrace(); 
    return Collections.emptyList(); //fail 
} 

closeQuietly (BufferedInputStream, inputChannel, compressedData, InputStream);

Из того, что я понимаю, поток ввода по умолчанию не имеет эффективного метода пропуска, а также небуферизуется, что приводит к чрезвычайно медленной декомпрессии.

Смежные вопросы