在Java中有效地通过套接字发送大型int

我正在开发一个Java应用程序,我需要尽快通过套接字连接从一部Android手机向另一部Android手机发送500,000个整数数组。 主要的瓶颈似乎是转换整数,因此套接字可以使用它们,无论我使用ObjectOutputStreams,ByteBuffers还是低级掩码和移位转换。 通过套接字将int []从一个Java应用程序发送到另一个Java应用程序的最快方法是什么?

这是我迄今为止尝试过的所有内容的代码,LG Optimus V上的基准测试我正在测试(600 MHz ARM处理器,Android 2.2)。

低级掩码和移位:0.2秒

public static byte[] intToByte(int[] input) { byte[] output = new byte[input.length*4]; for(int i = 0; i >> 8); output[i*4 + 2] = (byte)((input[i] & 0xFF0000) >>> 16); output[i*4 + 3] = (byte)((input[i] & 0xFF000000) >>> 24); } return output; } 

使用ByteBuffer和IntBuffer:0.75秒

 public static byte[] intToByte(int[] input) { ByteBuffer byteBuffer = ByteBuffer.allocate(input.length * 4); IntBuffer intBuffer = byteBuffer.asIntBuffer(); intBuffer.put(input); byte[] array = byteBuffer.array(); return array; } 

ObjectOutputStream:3.1秒(我尝试使用DataOutPutStream和writeInt()而不是writeObject()的变体,但它没有太大区别)

 public static void sendSerialDataTCP(String address, int[] array) throws IOException { Socket senderSocket = new Socket(address, 4446); OutputStream os = senderSocket.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream (os); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(array); oos.flush(); bos.flush(); os.flush(); oos.close(); os.close(); bos.close(); senderSocket.close(); } 

最后,我用来发送byte []的代码比intToByte()函数多0.2秒

 public static void sendDataTCP(String address, byte[] data) throws IOException { Socket senderSocket = new Socket(address, 4446); OutputStream os = senderSocket.getOutputStream(); os.write(data, 0, data.length); os.flush(); senderSocket.close(); } 

我在套接字的两边编写代码,所以我可以尝试任何types的字节顺序,压缩,序列化等。必须有一种方法在Java中更有效地进行这种转换。 请帮忙!

正如我在评论中指出的那样,我认为你正在抨击处理器的极限。 由于这可能对其他人有帮助,我会将其分解。 这是将整数转换为字节的循环:

  for(int i = 0; i < input.length; i++) { output[i*4] = (byte)(input[i] & 0xFF); output[i*4 + 1] = (byte)((input[i] & 0xFF00) >>> 8); output[i*4 + 2] = (byte)((input[i] & 0xFF0000) >>> 16); output[i*4 + 3] = (byte)((input[i] & 0xFF000000) >>> 24); } 

该循环执行500,000次。 600Mhz处理器每秒可处理大约600,000,000次操作。 因此,对于每个操作,循环的每次迭代将消耗大约1/1200秒。

再次,使用非常粗略的数字(我不知道ARM指令集,因此每个操作可能有更多或更少),这是一个操作计数:

  • 测试/分支:5(检索计数器,检索数组长度,比较,分支,增量计数器)
  • 掩码和移位:10 x 4(检索计数器,检索输入数组基础,添加,检索掩码,移位,乘法计数器,添加偏移量,添加到输出基数,存储)

好的,所以在粗略的数字中,这个循环最多需要55/1200秒,或0.04秒。 但是,您没有处理最佳案例场景。 首先,对于这么大的数组,您不会从处理器缓存中受益,因此您将在每个数组存储和加载中引入等待状态。

另外,我描述的基本操作可能会或可能不会直接转换为机器代码。 如果不是(我怀疑没有),那么循环的成本将超过我所描述的。

最后,如果你真的不走运,JVM还没有JIT编写你的代码,所以对于循环的某些部分(或全部)它解释字节码而不是执行本机指令。 我不太了解Dalvik对此发表评论。

Java是IMO从未打算能够有效地将内存区域从int[]重新解释为byte[]就像你在C中所做的那样。它甚至没有这样的内存地址模型。

您需要本地发送数据,或者您可以尝试查找一些微优化。 但我怀疑你会获得很多。

例如,这可能比您的版本略快(如果它可以工作)

 public static byte[] intToByte(int[] input) { byte[] output = new byte[input.length*4]; for(int i = 0; i < input.length; i++) { int position = i << 2; output[position | 0] = (byte)((input[i] >> 0) & 0xFF); output[position | 1] = (byte)((input[i] >> 8) & 0xFF); output[position | 2] = (byte)((input[i] >> 16) & 0xFF); output[position | 3] = (byte)((input[i] >> 24) & 0xFF); } return output; } 

我会这样做:

 Socket senderSocket = new Socket(address, 4446); OutputStream os = senderSocket.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(os); DataOutputStream dos = new DataOutputStream(bos); dos.writeInt(array.length); for(int i : array) dos.writeInt(i); dos.close(); 

另一方面,请阅读:

 Socket recieverSocket = ...; InputStream is = recieverSocket.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is); DataInputStream dis = new DataInputStream(bis); int length = dis.readInt(); int[] array = new int[length]; for(int i = 0; i < length; i++) array[i] = dis.readInt(); dis.close(); 

如果您不喜欢使用库,则可能需要查看Google的Protocol Buffers 。 它是为更复杂的对象序列化而构建的,但我敢打赌,他们努力想弄清楚如何在Java中快速序列化整数数组。

编辑:我查看了Protobuf源代码,它使用类似于你的低级掩码和移位的东西。