为什么 FileInputStream 比具有相同缓冲区大小的 BufferedInputStream 快得多
Why FileInputStream is much faster then BufferedInputStream with the same buffer size
这里有两段代码是这样的:
FileInputStream is = new FileInputStream(tmp);
byte[] buf = new byte[1024];
while (is.read(buf) > -1) {
}
和
BufferedInputStream is = new BufferedInputStream(new FileInputStream(tmp),1024);
while (is.read() > -1) {
}
从 BufferedInputStream
源代码看来,它们将花费相同的时间,但实际上第一种方式运行得更快(166 毫秒对 200M 文件的 5159 毫秒)。为什么?
FileInputStream#read(byte b[])
每次调用都会将多个字节读入 b
。在这种情况下 1024
BufferedInputStream#read()
每次调用都会读取一个字节。在内部 BufferedInputStream
将使用大小为 1024
的缓冲区从它包装的流中复制数据,但是,您执行的操作仍然比您必须执行的操作多得多。
尝试使用 BufferedInputStream#read(byte b[])
方法,您会发现速度与 FileInputStream
相当。
还如 OldCurmudgeon 所述,BufferedInputStream#read
方法已同步:
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
为了向您展示这可能有多少开销的示例,我做了一个小演示:
public class Main {
static final double TEST_SIZE = 100000000.0;
static final double BILLION = 1000000000.0;
public static void main(String[] args) {
testStandard();
testSync();
}
static void testStandard() {
long startTime = System.nanoTime();
for (int i =0; i < TEST_SIZE; i++) {
}
long endTime = System.nanoTime();
System.out.println((endTime - startTime)/ BILLION + " seconds");
}
static void testSync() {
long startTime = System.nanoTime();
for (int i =0; i < TEST_SIZE; i++) {
synchronized (Main.class) {}
}
long endTime = System.nanoTime();
System.out.println((endTime - startTime)/ BILLION + " seconds");
}
}
在我的电脑上,同步调用的执行时间要长大约 40 倍:
0.13086644 seconds
4.90248797 seconds
这里有两段代码是这样的:
FileInputStream is = new FileInputStream(tmp);
byte[] buf = new byte[1024];
while (is.read(buf) > -1) {
}
和
BufferedInputStream is = new BufferedInputStream(new FileInputStream(tmp),1024);
while (is.read() > -1) {
}
从 BufferedInputStream
源代码看来,它们将花费相同的时间,但实际上第一种方式运行得更快(166 毫秒对 200M 文件的 5159 毫秒)。为什么?
FileInputStream#read(byte b[])
每次调用都会将多个字节读入 b
。在这种情况下 1024
BufferedInputStream#read()
每次调用都会读取一个字节。在内部 BufferedInputStream
将使用大小为 1024
的缓冲区从它包装的流中复制数据,但是,您执行的操作仍然比您必须执行的操作多得多。
尝试使用 BufferedInputStream#read(byte b[])
方法,您会发现速度与 FileInputStream
相当。
还如 OldCurmudgeon 所述,BufferedInputStream#read
方法已同步:
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
为了向您展示这可能有多少开销的示例,我做了一个小演示:
public class Main {
static final double TEST_SIZE = 100000000.0;
static final double BILLION = 1000000000.0;
public static void main(String[] args) {
testStandard();
testSync();
}
static void testStandard() {
long startTime = System.nanoTime();
for (int i =0; i < TEST_SIZE; i++) {
}
long endTime = System.nanoTime();
System.out.println((endTime - startTime)/ BILLION + " seconds");
}
static void testSync() {
long startTime = System.nanoTime();
for (int i =0; i < TEST_SIZE; i++) {
synchronized (Main.class) {}
}
long endTime = System.nanoTime();
System.out.println((endTime - startTime)/ BILLION + " seconds");
}
}
在我的电脑上,同步调用的执行时间要长大约 40 倍:
0.13086644 seconds
4.90248797 seconds