2013-11-18 2 views
2

я следующий кусок тестового кода:ChannelInputStream пропустить метод очень медленный

try { 
     InputStream is; 
     Stopwatch.start("FileInputStream"); 
     is = new FileInputStream(imageFile.toFile()); 
     is.skip(1024*1024*1024); 
     is.close(); 
     Stopwatch.stop(); 

     Stopwatch.start("Files.newInputStream"); 
     is = Files.newInputStream(imageFile); 
     is.skip(1024*1024*1024); 
     is.close(); 
     Stopwatch.stop(); 
    } 
    catch(Exception e) 
    { 

    } 

и получил следующий вывод:

Start: FileInputStream 
FileInputStream : 0 ms 
Start: Files.newInputStream 
Files.newInputStream : 3469 ms 

ли вы какие-либо идеи, что происходит? Почему во втором случае пропустить так медленно?

Мне нужно использовать InputStreams, полученные из каналов, потому что мой тест показал, что лучше всего для моей задачи иметь одновременное чтение двух потоков из файла (и я могу заметить любое улучшение только тогда, когда использую Streams from Channels).

Во время тестов я понял, что я могу сделать что-то вроде этого:

SeekableByteChannel sbc = Files.newByteChannel(imageFile); 
    sbc.position(1024*1024*1024); 
    is = Channels.newInputStream(sbc); 

, который принимает только ср. 28ms, но это не очень помогает мне, потому что для использования этого я должен был бы сделать основные изменения API.

Моя платформа:

Linux galileo 3.11.0-13-generiC#20-Ubuntu SMP Wed Oct 23 07:38:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux 
java version "1.7.0_45" 
Java(TM) SE Runtime Environment (build 1.7.0_45-b18) 
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode) 

ответ

1

Глядя на источник, представляется, что реализация по умолчанию skip() фактически прочитывая (и отбрасывание) содержание потока до тех пор, пока не достигнет заданного положения:

public long skip(long n) throws IOException { 
    long remaining = n; 
    int nr; 

    if (n <= 0) { 
     return 0; 
    } 

    int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining); 
    byte[] skipBuffer = new byte[size]; 
    while (remaining > 0) { 
     nr = read(skipBuffer, 0, (int)Math.min(size, remaining)); 
     if (nr < 0) { 
      break; 
     } 
     remaining -= nr; 
    } 

    return n - remaining; 
} 

Метод SeekableByteChannel#position(), вероятно, просто обновляет указатель смещения, который фактически не требует ввода/вывода. Предположительно, FileInputStream переопределяет метод skip() с аналогичной оптимизацией. Документация поддерживает эту теорию:

Этот метод может пропускать больше байтов, чем остальные в файле резервной копии. Это не вызывает исключения, и количество пропущенных байтов может включать в себя некоторое количество байтов, которые были выше EOF файла резервной копии. Попытка чтения из потока после пропусков через конец приведет к -1, указывающему конец файла.

На дисках с дисками или на сетевом хранилище это может оказать существенное влияние.

+0

Что вы думаете - это ошибка в реализации ChannelInputStream? Почему есть чтение вместо вызова 'position()'? – czajah

+1

Это похоже только на ошибку, потому что вы имеете дело с файлами. 'ChannelInputStream' не относится к файлам; он может, например, обернуть поток, который не поддерживает переход к произвольной позиции. Рассмотрим сетевой поток: он не имеет фиксированной длины, и вы не можете «прыгать вперед», не читая какие-либо данные, предшествующие местоположению поиска. Почему 'Files.newInputStream()' создает 'ChannelInputStream' вместо' FileInputStream', является правильным вопросом, и у меня нет ответа для вас. –

+0

Итак, я оставлю это без сообщения об ошибке. Я думаю, что самый простой вариант для меня - обернуть канал в моей собственной реализации InputStream, который я смогу передать моему API. – czajah

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