Как повысить производительность при чтении InputStream? - PullRequest
0 голосов
/ 01 июля 2011

Очень хорошо, что это может быть просто момент KISS, но я чувствую, что должен все равно спросить.

У меня есть поток, и он читает из сокетов InputStream.Поскольку я имею дело с особенно маленькими размерами данных (поскольку данные, от которых я могу ожидать получения порядка 100–200 байт), я установил размер буферного массива равным 256. Как часть моей функции чтения, у меня естьпроверьте, что при чтении из InputStream я получу все данные.Если я этого не сделаю, то я буду рекурсивно вызывать функцию чтения снова.Для каждого рекурсивного вызова я объединяю два буферных массива вместе.

Моя проблема в том, что, хотя я никогда не ожидаю использовать больше, чем буфер 256, я хочу быть в безопасности.Но если овцы начинают летать, и буфер становится значительно больше, функция чтения (по оценкам) начнет занимать экспоненциальную кривую больше времени для завершения.

Как я могу увеличить эффективность функции чтения и /или объединение буфера?

Вот функция чтения в том виде, в каком она есть.

int BUFFER_AMOUNT = 256;

private int read(byte[] buffer) throws IOException {
   int bytes = mInStream.read(buffer); // Read the input stream

   if (bytes == -1) { // If bytes == -1 then we didn't get all of the data

        byte[] newBuffer = new byte[BUFFER_AMOUNT]; // Try to get the rest
        int newBytes;
        newBytes = read(newBuffer); // Recurse until we have all the data

        byte[] oldBuffer = new byte[bytes + newBytes]; // make the final array size

        // Merge buffer into the begining of old buffer.
        // We do this so that once the method finishes, we can just add the 
        // modified buffer to a queue later in the class for processing.
        for (int i = 0; i < bytes; i++) 
            oldBuffer[i] = buffer[i];

        for (int i = bytes; i < bytes + newBytes; i++) // Merge newBuffer into the latter half of old Buffer
            oldBuffer[i] = newBuffer[i];
        // Used for the recursion

        buffer = oldBuffer; // And now we set buffer to the new buffer full of all the data.
        return bytes + newBytes;
    }
    return bytes;
}

РЕДАКТИРОВАТЬ: я параноик (неоправданно) и должен просто установить буфер на 2048 и вызвать его сделать?

Ответы [ 3 ]

2 голосов
/ 01 июля 2011

BufferedInputStream, как заметил Роланд, и DataInputStream.readFully(), который заменяет весь код цикла

0 голосов
/ 01 июля 2011

Понятия не имею, что вы подразумеваете под "маленькими размерами данных". Вы должны измерить, тратится ли время в режиме ядра (тогда вы выдаете слишком много read s непосредственно на сокет) или в режиме пользователя (тогда ваш алгоритм слишком сложен).

В первом случае просто оберните ввод BufferedInputStream с 4096 байтами буфера и прочитайте из него.

В последнем случае просто используйте этот код:

/**
  * Reads as much as possible from the stream.
  * @return The number of bytes read into the buffer, or -1
  *         if nothing has been read because the end of file has been reached.
  */
static int readGreedily(InputStream is, byte[] buf, int start, int len) {
  int nread;
  int ptr = start; // index at which the data is put into the buffer
  int rest = len; // number of bytes that we still want to read

  while ((nread = is.read(buf, ptr, rest)) > 0) {
    ptr += nread;
    rest -= nread;
  }

  int totalRead = len - rest;
  return (nread == -1 && totalRead == 0) ? -1 : totalRead;
}

Этот код полностью избегает создания новых объектов, вызова ненужных методов и, более того, это просто.

0 голосов
/ 01 июля 2011
int BUFFER_AMOUNT = 256;

Должно быть окончательным, если вы не хотите, чтобы оно менялось во время выполнения.

if (bytes == -1) {

Должно быть! =

Кроме того, я не совсем понимаю, что выПытаюсь сделать с этим кодом.Вы не могли бы пролить свет на это?

...