最近发现项目中的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 协议 ,转载请注明出处!