简体   繁体   中英

How can I increase performance on reading the InputStream?

This very well may just be a KISS moment, but I feel like I should ask anyway.

I have a thread and it's reading from a sockets InputStream. Since I am dealing in particularly small data sizes (as in the data that I can expect to recieve from is in the order of 100 - 200 bytes), I set the buffer array size to 256. As part of my read function I have a check that will ensure that when I read from the InputStream that I got all of the data. If I didn't then I will recursively call the read function again. For each recursive call I merge the two buffer arrays back together.

My problem is, while I never anticipate using more than the buffer of 256, I want to be safe. But if sheep begin to fly and the buffer is significantly more the read the function (by estimation) will begin to take an exponential curve more time to complete.

How can I increase the effiency of the read function and/or the buffer merging?

Here is the read function as it stands.

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;
}

EDIT: Am I being paranoid (unjustifiedly) and should just set the buffer to 2048 and call it done?

BufferedInputStream , as noted by Roland, and DataInputStream.readFully() , which replaces all the looping code.

int BUFFER_AMOUNT = 256;

Should be final if you don't want it changing at runtime.

if (bytes == -1) {

Should be !=

Also, I'm not entirely clear on what you're trying to accomplish with this code. Do you mind shedding some light on that?

I have no idea what you mean by "small data sizes". You should measure whether the time is spent in kernel mode (then you are issuing too many read s directly on the socket) or in user mode (then your algorithm is too complicated).

In the former case, just wrap the input with a BufferedInputStream with 4096 bytes of buffer and read from it.

In the latter case, just use this code:

/**
  * 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;
}

This code completely avoids creating new objects, calling unnecessary methods and furthermore --- it is straightforward.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM