java - 在 Java 中通过套接字有效地发送大的 int[]

标签 java android performance sockets casting

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

这是迄今为止我尝试过的所有代码,以及我正在测试的 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;
}

使用 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();
}

我正在套接字的两侧编写代码,因此我可以尝试任何类型的字节顺序、压缩、序列化等。必须有一种方法可以在 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,因此对于循环的某些部分(或全部),它正在解释字节码而不是执行 native 指令。我对 Dalvik 了解不够,无法对此发表评论。

关于java - 在 Java 中通过套接字有效地发送大的 int[],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12320000/

相关文章:

java - 如果 JPA 查询花费太长时间,则关闭数据库 session

c# - Bentley-Ottmann 算法实现

java - 拖放 gwt

python - 提高比较 pandas 数据帧行的 for 循环的性能

performance - 一种功能切换类型与多种类型的功能

java - Hibernate Criteria 中最多有两个日期列

android - 如何在 Android Table Layout 中获得水平和垂直滚动条

android - 在安卓中开始游戏

android - 微调器在我的 Kotlin fragment 中不起作用

JavaScript if 语句优化