我刚从这个论坛复制了一个working example数据传输,并且在我的程序中使用它几乎没有变化,但我无法看到它的速度有什么问题。我测试了主要示例,它在不到30ms的时间内传输了大约1MB。读写速度都非常好。但是当我在我的情况下使用它时,相同数量的数据不会在不到400毫秒的时间内传输!写作仍然有效,但阅读有点问题。
这里写入数据。现在,我并没有试图加速第一部分,即对象的序列化。我的问题是关于第二部分。
private static void writeObject(OutputStream out, Object obj) throws IOException {
long t1 = System.currentTimeMillis();
ByteArrayOutputStream bArr = new ByteArrayOutputStream();
ObjectOutputStream ojs = new ObjectOutputStream(bArr);
ojs.writeObject(obj);
ojs.close();
long t2 = System.currentTimeMillis();
byte[] arr = bArr.toByteArray();
int len = arr.length;
for (int i = 0; i < arr.length; i += BUFFER_SIZE)
out.write(arr, i, Math.min(len - i, BUFFER_SIZE));
out.close();
long t3 = System.currentTimeMillis();
System.out.println(t3 - t2);
}
嗯,这不是那么糟糕! t3 - t2
打印约30毫秒。
问题在于readObject()
,而不是在第二部分中,对象被反序列化,至少现在不是,但问题出在第一部分,其中t2 - t1
转正如我所提到的,超过400毫秒。
private static Object readObject(InputStream in) throws IOException, ClassNotFoundException {
long t1 = System.currentTimeMillis();
ByteArrayOutputStream bao = new ByteArrayOutputStream();
byte[] buff = new byte[BUFFER_SIZE];
int read;
while ((read = in.read(buff)) != -1) {
bao.write(buff, 0, read);
}
in.close();
long t2 = System.currentTimeMillis();
ByteArrayInputStream bArr = new ByteArrayInputStream(bao.toByteArray());
Object o = new ObjectInputStream(new BufferedInputStream(bArr)).readObject();
long t3 = System.currentTimeMillis();
System.out.println(t2 - t1);
return o;
}
这是main()
:
final static int BUFFER_SIZE = 64 * 1024;
public static void main(String[] args) throws Exception {
final String largeFile1 = "store.aad";
final Table t = (Table) new ObjectInputStream(new FileInputStream(largeFile1)).readObject();
new Thread(new Runnable() {
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(12345);
Socket clientSocket = serverSocket.accept();
readObject(clientSocket.getInputStream());
} catch (Exception e) {
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
Socket socket = new Socket("localhost", 12345);
OutputStream socketOutputStream = socket.getOutputStream();
writeObject(socketOutputStream, t);
} catch (Exception e) {
}
}
}).start();
}
我哪里错了?!
答案 0 :(得分:0)
(关于the difficulty of getting Java benchmarks correct的强制性评论)。
您似乎正在启动两个线程,一个读者线程和一个编写器线程。事情按以下顺序进行是完全可行的:
t1
。read()
,但由于尚无可用数据而被阻止。write()
。read()
调用返回。t2
等,然后退出。现在,如果你看到t2 - t1
约400毫秒,这可能不是正在发生的事情:似乎编写线程对sleep()
的调用必须在t1
之前发生。记录。但简短的回答是,似乎不清楚t2 - t1
正在衡量什么。特别是,期望它仅仅衡量read()
完成工作的时间(而不是等待数据读取)似乎是不正确的。
答案 1 :(得分:0)
如果要使用缓冲IO进行读写,可以分别使用BufferedInputStream
和BufferedOutputStream
进行读写。而且,您可以使用try-with-resources
Statement来关闭。写,像
private static final int BUFFER_SIZE = 32 * 1024;
private static void writeObject(OutputStream out, Object obj) //
throws IOException {
try (ObjectOutputStream ojs = new ObjectOutputStream(//
new BufferedOutputStream(out, BUFFER_SIZE));
ojs.writeObject(obj);
}
}
并阅读
private static Object readObject(InputStream in) throws IOException,//
ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(//
new BufferedInputStream(in, BUFFER_SIZE))) {
return ois.readObject();
}
}
答案 2 :(得分:0)
当您执行微基准测试时,我建议您忽略至少前2秒CPU时间的所有结果,以便让JVM有机会进行预热。
我会在不使用睡眠的情况下写这个。
出于测试的目的,编写对象是无关紧要的。您只需要编写new byte[size]
并查看需要多长时间。
为了测试短暂的延迟,我会使用System.nanoTime()
我首先要写一条小信息然后查看往返时间。即客户端将数据包发送到服务器,然后服务器再次发送回来。
最后但并非最不重要的是,通过使用Java 1.4(2004)中添加的NIO,您将获得更好的性能
以前是一些代码写的EchoServerMain和EchoClientMain会产生这样的结果。
On a E5-2650 v2 over loopback
Throughput was 2880.4 MB/s
Loop back echo latency was 5.8/6.2 9.6/19.4 23.2us for 50/90 99/99.9 99.99%tile
注意:这些时间是将数据包发送到服务器并再次返回的完整往返时间。时间以微秒为单位。
答案 3 :(得分:0)
我刚刚复制了一个工作示例......
不,你没有。你制造了完全不同的东西。
int len = arr.length;
for (int i = 0; i < arr.length; i += BUFFER_SIZE)
out.write(arr, i, Math.min(len - i, BUFFER_SIZE));
这个循环完全是胡说八道。它可以完全替换为
out.write(arr, 0, len);
然而,你只是增加了延迟并浪费了所有这些空间 private static void writeObject(OutputStream out,Object obj)throws IOException { long t1 = System.currentTimeMillis(); out.writeObject(OBJ); out.close(); long t2 = System.currentTimeMillis();
System.out.println(t2-t1);
}
ByteArrayOutputStream
中没有任何意义,将更多字节写入真实ObjectOutputStream
只是无效。在基准测试操作中没有任何意义,这些操作永远不应该发生。
为什么你关闭ObjectOutputStream
是另一个谜。并且可能在接收端你有类似的代码:用ObjectInputStream.readObject().