Неожиданное длительное время обработки при чтении байтового массива - PullRequest
1 голос
/ 02 августа 2010

У меня есть программа, которая должна обрабатывать источник байтового массива.Изначально программа работала нормально, когда размер байтового массива составляет 3000 байт.Теперь размер данных увеличивается, а размер массива необходимо изменить с 3000 до 30000 (в 10 раз).

Я создаю пример программы для тестирования, чтобы проверить время цикла.Я полагаю, что требуемое время ЦП должно быть линейно увеличено в соответствии с размером массива, но тестовая программа показывает, что для процесса 30000 байт требуется намного больше, чем в 35 раз по сравнению с процессом 3000 байт.

Вот моя программа оценки производительности.Может ли программа улучшиться так, чтобы она использовала только в 10 раз больше процессорного времени?

public static void main(String args[])

    int TestArraySize=30000;
    String strFinalMessage="";

    // create a dummy byte array
    byte[] bytearrayMessageContent = new byte[TestArraySize];
    for (int i=0; i<TestArraySize; i++) {
        // fill character A-J into the dummy array
        bytearrayMessageContent[i] = (byte) (i%10+65); 
    }
    System.out.println(bytearrayMessageContent.length);

    // time start time
    long lngCurrentTime = System.currentTimeMillis();

    // process the byte array
    int intTHMessageLenAdj = TestArraySize;
    try {
        InputStream input = new ByteArrayInputStream(bytearrayMessageContent);
        while (intTHMessageLenAdj > 0) {
            // get random length of bytes to process
            int RandomLength = getNextRandom();
            if (RandomLength > intTHMessageLenAdj) {
                RandomLength = intTHMessageLenAdj;
            }

            // get the bytes to be process in a byte array and process it
            byte[] bytearrayMsgTrunk = new byte[RandomLength];
            input.read(bytearrayMsgTrunk);
            // do some logic here
            strFinalMessage += new String(bytearrayMsgTrunk) + "||";

            // repeat looping until all bytes are read
            intTHMessageLenAdj -= RandomLength;
        }
        input.close();  
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    // time end time
    lngCurrentTime = System.currentTimeMillis() - lngCurrentTime;
    //System.out.println(strFinalMessage);
    System.out.println(lngCurrentTime);
}

public static int getNextRandom() { 
    // info is arround 4 bytes size
    Random random = new Random();
    return random.nextInt(8);
}

Ответы [ 3 ]

2 голосов
/ 02 августа 2010

Я полагаю, что требуемое время ЦП должно быть линейно увеличено в соответствии с размером массива, но тестовая программа показывает, что процесс 30000 байт требует гораздо более 35 раз по сравнению с процессом 3000 байт.

На самом деле, я ожидаю, что он будет расти квадратично с размером массива.Если бы вы профилировали программу, вы, вероятно, обнаружили бы, что значительная часть времени идет на звонки на String.concat.И когда массив становится больше, пропорция будет увеличиваться.

По сути, каждый раз, когда вы делаете конкатенацию строк, вы копируете все накопленные вами символы в новую строку ... и выбрасываете предыдущий.Нетрудно видеть, что эта часть кода имеет вид O(N**2), где N - размер массива.

Замените объявление String и конкатенации на это:

// allocate the builder with extra space to hold the '||' characters
StringBuilder sb= new StringBuilder(TestArraySize * 3 / 2);
...
// this replaces the concatenation.
sb.append(new String(bytearrayMsgTrunk);
sb.append("||");
...
// this does a final copy of the characters to create a new String
String strFinalMessage = sb.toString();
2 голосов
/ 02 августа 2010

Ну, здесь есть несколько проблем:

  • Используется кодировка платформы по умолчанию для строк.Не делай этого.Укажите конкретную строковую кодировку для преобразования между байтами и текстом.
  • Не объединяйте строки в такой цикл - используйте StringBuilder.
  • Вы игнорируете возвращаемое значение InputStream.Read.Это может быть хорошо при чтении из ByteArrayInputStream, но вы, как правило, не должны на это полагаться.
  • Каждый раз вы создаете новый экземпляр Random.Я считаю, что это нормально с Java 6, но даст вам повторные значения в более ранних версиях.Обычно это плохая идея.Повторно используйте один экземпляр Random.
0 голосов
/ 02 августа 2010

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

...