安卓在Java中通过socket高效地发送大int[]
我正在开发一个Java应用程序,在这个应用程序中,我需要通过socket连接尽快将500000个整数的数组从一部Android手机发送到另一部Android手机。主要的瓶颈似乎是转换整数,以便socket可以接受它们,无论我使用ObjectOutputStreams、ByteBuffers还是低级掩码和移位转换。通过socket将int[]从一个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 < 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);
}
return output;
}
使用字节缓冲区和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();
}
我在socket的两侧编写代码,这样我就可以尝试任何类型的endianness、压缩、序列化等。必须有一种方法在Java中更有效地进行这种转换。请帮忙
# 1 楼答案
Java从来没有像在C中那样,能够有效地从
int[]
到byte[]
重新解释内存区域。它甚至没有这样的内存地址模型您要么需要使用本地方式发送数据,要么可以尝试找到一些微优化。但我怀疑你会收获很多
例如,这可能比你的版本快一点(如果可以的话)
# 2 楼答案
正如我在评论中指出的,我认为你正在挑战处理器的极限。因为这可能对其他人有帮助,所以我将详细介绍。下面是将整数转换为字节的循环:
这个循环执行了500000次。600Mhz处理器每秒可以处理大约600000000次操作。因此,循环的每次迭代将为每次操作消耗大约1/1200秒的时间
同样,使用非常粗略的数字(我不知道ARM指令集,所以每个操作可能或多或少),这里是一个操作计数:
好的,在粗略的数字中,这个循环最多需要55/1200秒,或者0.04秒。然而,你并不是在处理最好的情况。首先,对于这么大的阵列,你不会从处理器缓存中受益,所以你会在每个阵列存储和加载中引入等待状态
另外,我描述的基本操作可能会也可能不会直接转化为机器代码。如果没有(我怀疑没有),这个循环的成本将比我描述的要高
最后,如果你真的很不走运,JVM没有JIT你的代码,所以对于循环的部分(或全部)来说,它是在解释字节码,而不是执行本机指令。我对Dalvik了解不够,无法对此发表评论
# 3 楼答案
如果你不反对使用图书馆,你可能想从谷歌上查一查Protocol Buffers。它是为更复杂的对象序列化而构建的,但我敢打赌,他们努力研究如何在Java中快速序列化整数数组
编辑:我查看了Protobuf源代码,它使用了类似于低级掩码和移位的东西