我创建了一个非常简单的.proto文件:
syntax = "proto2";
package Metadata;
option java_package = "metadata";
option java_outer_classname = "Metadata";
option optimize_for=SPEED;
message PutMessage {
optional string key =1;
optional int64 dt = 2;
}
我创建了一个简单的客户端 - 服务器程序,服务器回应客户端消息。所有消息都是PutMessage:
服务器:
public class Server {
public static void main(String args[]) throws IOException, InterruptedException {
ServerSocket ss = new ServerSocket(8080);
System.out.println("Listening for client");
Socket socket = ss.accept();
System.out.println("Server Results: ");
while (true) {
Long parseStart = System.nanoTime();
PutMessage sm = PutMessage.parseDelimitedFrom(socket.getInputStream());
Long parseEnd = System.nanoTime();
Long writeStart = System.nanoTime();
sm.writeDelimitedTo(socket.getOutputStream());
Long writeEnd = System.nanoTime();
System.out.println("Parse time: " + (parseEnd - parseStart));
System.out.println("Write time: " + (writeEnd - writeStart));
}
}
}
客户端:
public class Client {
public static void main (String args[]) throws IOException, InterruptedException{
Socket socket = new Socket("127.0.0.1", 8080);
int A = new Integer(args[0]);
PutMessage cm = PutMessage.newBuilder().setDt(3434).setKey("sdfwsdf").build();
System.out.println("Client Results7: ");
for (int i=0;i < A; i++){
Long writeStart = System.nanoTime();
cm.writeDelimitedTo(socket.getOutputStream());
Long writeEnd = System.nanoTime();
Long parseStart = System.nanoTime();
cm.parseDelimitedFrom(socket.getInputStream());
Long parseEnd = System.nanoTime();
System.out.println("Write time: " + (writeEnd - writeStart));
System.out.println("Parse time: " + (parseEnd - parseStart));
}
}
}
当我在Windows上运行客户端和服务器时,速度非常快。但是当我在Ubuntu上运行时,服务器需要很长时间(70(ms))来解析客户端消息:当我将3传递给客户端时,这些是一些结果:
全部以纳秒为单位
视窗:
Client Results:
Write time: 54401508
Parse time: 95818962
Write time: 279563
Parse time: 201593
Write time: 200568
Parse time: 138500
Server Results:
Parse time: 207099065
Write time: 42572640
Parse time: 20808241
Write time: 156966
Parse time: 209801
Write time: 124649
Ubuntu的:
Client Results:
Write time: 31205019
Parse time: 86399222
Write time: 101132
Parse time: 40619478
Write time: 214496
Parse time: 79164985
Server Results:
Parse time: 183947743
Write time: 25819286
Parse time: 28680184
Write time: 292955
Parse time: 79299932
Write time: 298012
我发现,如果我从put消息中删除setDt,当它只是setKey时,它在Ubuntu上也很快。但我需要dt。我不知道为什么它在Windows上速度快,在Ubuntu上速度慢。我想也许我的机器不同,但没有setDt它在Ubuntu上很快,所以问题不在于硬件。
我也试过proto3,结果相同。任何帮助是极大的赞赏。
更新:两个操作系统都是64位。 Java版本是:
Ubuntu:
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
Windows:
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)
由于
更新: 我在两个AWS EC2实例上重新进行了实验。一个Windows和另一个亚马逊Linux。这次我没有使用Ubuntu,但结果相同。我再次在Windows上获得了更快的结果。这真奇怪!
答案 0 :(得分:1)
我发现,如果我们写字节,而不是调用writDelimetedTo和parseDelimitedFrom,则没有延迟:
服务器:
public class CodedServer {
public static void main(String args[]) throws IOException, InterruptedException {
ServerSocket ss = new ServerSocket(8080);
System.out.println("Listening for client8");
Socket socket = ss.accept();
System.out.println("Server Results: ");
CodedOutputStream out = CodedOutputStream.newInstance(socket.getOutputStream());
CodedInputStream in = CodedInputStream.newInstance(socket.getInputStream());
while (true) {
Long parseStart = System.nanoTime();
int size = in.readInt32();
byte[] result = in.readRawBytes(size);
PutMessage cm = PutMessage.parseFrom(result);
Long parseEnd = System.nanoTime();
Long writeStart = System.nanoTime();
out.writeInt32NoTag(cm.getSerializedSize());
cm.writeTo(out);
out.flush();
Long writeEnd = System.nanoTime();
System.out.println("Parse time: " + (parseEnd - parseStart));
System.out.println("Write time: " + (writeEnd - writeStart));
}
}
}
客户:
public class CodedClient {
public static void main (String args[]) throws IOException, InterruptedException{
Socket socket = new Socket(args[0], 8080);
int A = new Integer(args[1]);
PutMessage cm = PutMessage.newBuilder().setDt("sdfsdfsdf").setKey("Test Stringdfgdsfgsdfgsdfgsdfgsdfgsdfgsdfgsdfgsdfgsdfgsdfgsdfg").build();
CodedOutputStream out = CodedOutputStream.newInstance(socket.getOutputStream());
CodedInputStream in = CodedInputStream.newInstance(socket.getInputStream());
System.out.println("Client Results9: ");
for (int i=0;i < A; i++){
Long writeStart = System.nanoTime();
out.writeInt32NoTag(cm.getSerializedSize());
cm.writeTo(out);
out.flush();
Long writeEnd = System.nanoTime();
Long parseStart = System.nanoTime();
int size = in.readInt32();
byte[] result = in.readRawBytes(size);
cm = PutMessage.parseFrom(result);
Long parseEnd = System.nanoTime();
System.out.println("Write time: " + (writeEnd - writeStart));
System.out.println("Parse time: " + (parseEnd - parseStart));
}
System.out.println(cm.toString());
}
}
我很高兴找到解决方案,但是我觉得为什么Google协议缓冲区实现两个标准功能会导致如此显着的延迟?
答案 1 :(得分:0)
您正在测量IO时间,而不是解析时间。如果要测量解析时间,请从字节数组或ByteArrayInputStream中解析。
在这种特殊情况下,Windows和Ubuntu之间的区别可能源于在实现更多数据之前等待一段时间的IO实现(为了减少数量开销)。我尝试的事情是在服务器上关闭或刷新流 - 或者只是在那里发送一些额外的数据。