Java 谷歌协议缓冲区,Windows上快,Ubuntu上慢

Java 谷歌协议缓冲区,Windows上快,Ubuntu上慢,java,ubuntu,protocol-buffers,Java,Ubuntu,Protocol Buffers,我创建了一个非常简单的.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; } 我有一个创建一个简单

我创建了一个非常简单的.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 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 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));
 }
 }
}
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) 
窗口:

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,另一个是Amazon Linux。这次我没有使用Ubuntu,但我得到了同样的结果。同样,我在Windows上获得了更快的结果。真奇怪

您测量的是IO时间,而不是解析时间。如果要测量分析时间,请从字节数组或ByteArrayInputStream进行分析


在这种特殊情况下,windows和Ubuntu之间的差异可能源于IO实现在数据移交之前等待一段时间以获取更多数据(以减少数据开销)。我会尝试关闭或刷新服务器上的流,或者只是发送一些额外的数据。

您测量的是IO时间,而不是解析时间。如果要测量分析时间,请从字节数组或ByteArrayInputStream进行分析


在这种特殊情况下,windows和Ubuntu之间的差异可能源于IO实现在数据移交之前等待一段时间以获取更多数据(以减少数据开销)。我会尝试关闭或刷新服务器上的流,或者只是在那里发送一些额外的数据。

我发现,如果我们写入字节,就不会有延迟,而不是调用writeDelimeterdTo和parseDelimitedFrom:

服务器:

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 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());
    }
}
公共类CodedClient{
公共静态void main(字符串args[])引发IOException、InterruptedException{
插座=新插座(参数[0],8080);
int A=新整数(args[1]);
PutMessage cm=PutMessage.newBuilder().setDt(“sdfsdfsdf”).setKey(“测试字符串DFGDSFGSDFGSDFGSDFGSDFGSDFGSDFGSDFGSDFGSDFG”).build();
CodedOutputStream out=CodedOutputStream.newInstance(socket.getOutputStream());
CodedInputStream in=CodedInputStream.newInstance(socket.getInputStream());
System.out.println(“客户端结果9:”);
for(int i=0;i

我很高兴找到一个解决方案,但我想知道为什么谷歌协议缓冲区实现两个标准函数会造成如此大的延迟

我发现,如果我们写入字节,就没有延迟,而不是调用writeDelimeterdTo和parseDelimitedFrom:

服务器:

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 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());
    }
}
公共类CodedClient{
公共静态void main(字符串args[])引发IOException、InterruptedException{
插座=新插座(参数[0],8080);
int A=新整数(args[1]);
PutMessage cm=PutMessage.newBuilder().setDt(“sdfsdfsdf”).setKey(“测试字符串DFGDSFGSDFGSDFGSDFGSDFGSDFGSDFGSDFGSDFGSDFG”).build();
CodedOutputStream out=CodedOutputStream.newInstance(socket.getOutputStream());
CodedInputStream in=CodedInputStream.newInstance(socket.getInputStream());
System.out.println(“客户端结果9:”);
for(int i=0;i

我很高兴找到一个解决方案,但我想知道为什么谷歌协议缓冲区实现两个标准函数会造成如此大的延迟

您在Linux端和Windows端使用的是什么JVM?您使用的是服务器虚拟机还是客户端虚拟机?您是否正在预热JVM(看起来不像)?另请参见:。windows和Ubuntu的基准代码是相同的,为什么一个是快的,另一个是慢的?不是快或慢的代码。您所关心的是这些代码被JIT转换成什么,这在很大程度上取决于您运行它的JVM的确切版本,以及您传递给它的确切标志。如果没有这些信息,任何人唯一能帮你做的就是猜测。尝试将程序中与套接字相关的部分与protobuf部分分开,并独立地对它们进行基准测试也是很有用的。性能问题可能不是来自您期望的地方。。。e、 g.套接字流可能具有不同的性能,并且在一种情况下额外的8个字节可能会碰撞到一个in