最近发现项目中的NanoHttpD对于文件上传的处理相当慢,于是我在排查一些耗时的操作。当然,对于文件的读写操作带来的耗时是无法避免的。

首先,文件上传的处理需要使用IHTTPSession#parseBody()进行request的解码,主要的耗时操作也是发生在这个操作里边。
通过阅读代码,我发现parseBody()会先把整个request缓存到文件中,然后查找boundary,然后进行request的分割,最好存储到文件里去。
这样就会产生大量的io操作,这个也是速度慢的主要原因。
经过我的排查,我发现查找boundary的代码有过更新,当我使用新的getBoundaryPositions(),发现速度竟然提升了10倍左右,不禁吓的我贴出源码,以待日后学习、比较。

旧版代码

/**
 * Find the byte positions where multipart boundaries start.
 */
private int[] getBoundaryPositions(ByteBuffer b, byte[] boundary) {
    int matchcount = 0;
    int matchbyte = -1;
    List<Integer> matchbytes = new ArrayList<Integer>();
    for (int i = 0; i < b.limit(); i++) {
        if (b.get(i) == boundary[matchcount]) {
            if (matchcount == 0)
                matchbyte = i;
            matchcount++;
            if (matchcount == boundary.length) {
                matchbytes.add(matchbyte);
                matchcount = 0;
                matchbyte = -1;
            }
        } else {
            i -= matchcount;
            matchcount = 0;
            matchbyte = -1;
        }
    }
    int[] ret = new int[matchbytes.size()];
    for (int i = 0; i < ret.length; i++) {
        ret[i] = matchbytes.get(i);
    }
    return ret;
}

新版代码

/**
 * Find the byte positions where multipart boundaries start.
 */
private int[] getBoundaryPositions(ByteBuffer b, byte[] boundary) {
    int[] res = new int[0];
    if (b.remaining() < boundary.length) {
        return res;
    }
    int search_window_pos = 0;
    byte[] search_window = new byte[4 * 1024 + boundary.length];
    int first_fill = (b.remaining() < search_window.length) ? b.remaining() : search_window.length;
    b.get(search_window, 0, first_fill);
    int new_bytes = first_fill - boundary.length;
    do {
        // Search the search_window
        for (int j = 0; j < new_bytes; j++) {
            for (int i = 0; i < boundary.length; i++) {
                if (search_window[j + i] != boundary[i])
                    break;
                if (i == boundary.length - 1) {
                    // Match found, add it to results
                    int[] new_res = new int[res.length + 1];
                    System.arraycopy(res, 0, new_res, 0, res.length);
                    new_res[res.length] = search_window_pos + j;
                    res = new_res;
                }
            }
        }
        search_window_pos += new_bytes;
        // Copy the end of the buffer to the start
        System.arraycopy(search_window, search_window.length - boundary.length, search_window, 0, boundary.length);
        // Refill search_window
        new_bytes = search_window.length - boundary.length;
        new_bytes = (b.remaining() < new_bytes) ? b.remaining() : new_bytes;
        b.get(search_window, boundary.length, new_bytes);
    } while (new_bytes > 0);
    return res;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

蒲公英 上一篇
一个牛B的网站:toptal.com 下一篇