Производительность при чтении и записи файлов, что лучше?Сериализация X Java.nio - PullRequest
0 голосов
/ 15 марта 2012

У меня есть объект с 1 int и 4 double.

Я сравнил производительность, чтобы записать 5 миллионов этих объектов в файл, используя сериализацию и объект FileChannel.

В сериализации используется следующий метод для чтения и записи файла.

    public void print() throws IOException, ClassNotFoundException{     
    ObjectInputStream input = new ObjectInputStream(new FileInputStream(this.filePath) );                   
    try {           
        while(true) {               
            this.sb = (Sbit) input.readObject();
            //System.out.println(this.sb.toString());
        } 
    }
    catch ( EOFException eofException ) {
        return; 
    } 
    catch (IOException ioException) {
        System.exit( 1 );
    }
    finally {
        if( input != null )
            input.close();
    } 

}   

public void build() throws IOException {        
    ObjectOutputStream output = new ObjectOutputStream( new FileOutputStream(this.filePath) );
    try {           
        Random random = new Random();
        for (int i = 0; i<5000000; i++) {
            this.sb = new Sbit();
            this.sb.setKey(i);
            this.sb.setXMin( random.nextDouble() );
            this.sb.setXMax( random.nextDouble() );
            this.sb.setYMin( random.nextDouble() );
            this.sb.setYMax( random.nextDouble() );

            output.writeObject(this.sb);
        }           
    } 
    catch (IOException ioException) {
        System.exit( 1 );
    } 
    finally {
        try {
            if( output != null)
                output.close();
        }
        catch ( Exception exception ) {
            exception.printStackTrace();
            System.exit(1);
        }
    }       
} 

При использовании java.nio было:

    public void print() throws IOException {    
    FileChannel file = new RandomAccessFile(this.filePath, "rw").getChannel();  
    ByteBuffer[] buffers = new ByteBuffer[5];
    buffers[0] = ByteBuffer.allocate(4);   // 4 bytes to int
    buffers[1] = ByteBuffer.allocate(8);   // 8 bytes to double
    buffers[2] = ByteBuffer.allocate(8);    
    buffers[3] = ByteBuffer.allocate(8);   
    buffers[4] = ByteBuffer.allocate(8);   

    while (true) {
        if(file.read(buffers[0]) == -1 )       // Read the int, 
            break;                                  // if its EOF exit the loop

        buffers[0].flip();

        this.sb = new Sbit();
        this.sb.setKey(buffers[0].getInt());

        if(file.read(buffers[1]) == -1) {   // Read the int primary value
            assert false;                   // Should not get here!
            break;                          // Exit loop on EOF
        }
        buffers[1].flip();

        this.sb.setXMin( buffers[1].getDouble() );

        if(file.read(buffers[2]) == -1) {   
            assert false;                   
            break;                          
        }
        buffers[2].flip();

        this.sb.setXMax( buffers[2].getDouble() );

        if(file.read(buffers[3]) == -1) {   
            assert false;                   
            break;                          
        }
        buffers[3].flip();

        this.sb.setYMin( buffers[3].getDouble() );
        if(file.read(buffers[4]) == -1) {   
            assert false;                   
            break;                          
        }
        buffers[4].flip();

        this.sb.setYMax( buffers[4].getDouble() );

        for(int i = 0; i < 5; i++)
            buffers[i].clear();

    } 

} 


public void build() throws IOException {    
    FileChannel file = new RandomAccessFile(this.filePath, "rw").getChannel();      

    Random random = new Random();
    for (int i = 0; i<5000000; i++) {
        this.sb = new Sbit();
        this.sb.setKey(i);
        this.sb.setXMin( random.nextDouble() );
        this.sb.setXMax( random.nextDouble() );
        this.sb.setYMin( random.nextDouble() );
        this.sb.setYMax( random.nextDouble() );

        ByteBuffer[] buffers = new ByteBuffer[5];
        buffers[0] = ByteBuffer.allocate(4);   // 4 bytes to into
        buffers[1] = ByteBuffer.allocate(8);   // 8 bytes to double
        buffers[2] = ByteBuffer.allocate(8);   
        buffers[3] = ByteBuffer.allocate(8);   
        buffers[4] = ByteBuffer.allocate(8);   

        buffers[0].putInt(this.sb.getKey()).flip(); 
        buffers[1].putDouble(this.sb.getXMin()).flip();
        buffers[2].putDouble(this.sb.getXMax()).flip();
        buffers[3].putDouble(this.sb.getYMin()).flip();
        buffers[4].putDouble(this.sb.getYMax()).flip();
        try {
            file.write(buffers);
        } 
        catch (IOException e)   {
            e.printStackTrace(System.err);
            System.exit(1);
        } 

        for(int x = 0; x < 5; x++)
            buffers[x].clear();

    }
}

Но я много читал о java.nio и пытался использовать его именно потому, что он имеет лучшую производительность. Но это не то, что произошло в моем случае.

Для записи файла были следующие (java.nio):

размер файла: 175 МБ время в миллисекундах: 57638

Использование сериализации:

размер файла: 200 МБ время в миллисекундах: 34504

Для чтения этого файла, были следующие (java.nio):

время в миллисекундах: 78172

Использование сериализации:

время в миллисекундах: 35288

Я что-то не так делаю в java.nio? Я хотел бы записать в те же двоичные файлы, что и сделано. Есть еще один способ эффективно написать файл? на самом деле сериализация объекта является лучшим способом?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 15 марта 2012

Вы создаете 25 000 000 объектов ByteBuffer, причем каждый ByteBuffer составляет не более 8 байтов. Это очень неэффективно.

Создайте только один ByteBuffer, выделяя его на 38 байт вне цикла (перед для инструкции)

Внутри цикла вы можете использовать тот же ByteBuffer, как указано ниже:

  buffer.clear();

  buffer.putInt(this.sb.getKey()); 
  buffer.putDouble(this.sb.getXMin());
  buffer.putDouble(this.sb.getXMax());
  buffer.putDouble(this.sb.getYMin());
  buffer.putDouble(this.sb.getYMax());

  buffer.flip();

  try
  {
     file.write(buffer);
  }
  catch (IOException ex)
  {
     ex.printStackTrace();
     //etc...
  }

  buffer.flip();

Попробуйте и дайте нам знать, если увидите какие-либо улучшения.

1 голос
/ 15 марта 2012

Вместо использования нескольких байтовых буферов объявите один байтовый буфер, достаточно большой, чтобы вместить все данные, которые вы хотите поместить в него. Затем вставьте в него данные, как сейчас. Когда закончите, переверните буфер и запишите его. Когда вы будете готовы прочитать его обратно, прочитайте данные с диска в байтовый буфер, переверните его, а затем прочитайте данные, используя getInt / getDouble.

0 голосов
/ 15 марта 2012

Я не пытался сериализовать вещи самостоятельно, но добился хороших результатов с kryo . Это намного быстрее, чем стандартная сериализация Java.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...