8

我需要通过两个 Android 设备之间的套接字发送一个包含 500,000 个整数的数组。目前,我花费大量时间将 int[] 转换为 byte[] 以便 Java 的套接字能够接受它(请参阅我之前的问题Efficiently send large int[] over sockets in Java,我们确定没有更快的方法在 Java 中进行类型转换)。

我现在的问题是,如果我采用 int[] 并通过 JNI 将其传递给 Android NDK,我是否可以期望对 byte[] 的类型转换在本机代码中更快?我知道在普通的 C 中将 int* 类型转换为 char* 非常简单,但是我想知道 JNI 是否会否定任何性能提升。

此外,一旦我的本机代码中有一个 byte[],我可以有效地将它传递回我的 Java 代码,还是我还需要在 C 中实现套接字?

编辑1:人们在没有点击链接的情况下发布了很多答案。使用 ByteBuffers 不是一个好的选择,它实际上比 mask-and-shift 慢得多,这仍然比我的性能关键代码需要慢得多!这就是我问NDK的原因。

编辑 2:我更改了上面的文字,说 C 代码可以从 int* 转换为 char* 而不是 int[] 转换为 byte[]。希望这能澄清这个问题。

编辑 3:为了澄清我的用例,这是一个研究问题,我在多个设备上分布大量整数并对列表进行并行排序。假设我在 Java 中有 500,000 个整数(不管它们来自哪里),我需要尽快通过套接字将它们从设备中取出。说“不要以整数数组开头”的答案没有帮助。此外,我的应用程序代码需要尽可能接近 100% Java。如果本机类型转换和套接字提高了性能,那没关系,但我不能在本机上做任何其他事情(即排序)。

4

3 回答 3

2

不,使用 JNI/NDK 不会提高性能。首先,当您尝试将数组转移到本机代码时,您必须复制它或使用直接分配的 ByteBuffer。原来 Dalvik VM 的实现总是从 Get*ArrayElements() 返回直接指针。我确实怀疑您是否会获得性能提升,因为通过 JNI 进行的调用会产生间接费用。最后,C++ 和 Java 在这种情况下具有非常接近的性能(请参阅C++ 性能与 Java/C#)。

看看这个问题和第一个答案,了解从 Java 将 int[] 转换为 byte[] 的快速方法How to convert int[] to byte[]

您是否有理由使用 int[] 而不是 byte[] 开始?如果是图像,我们可能会推荐避免转换的方法。

于 2012-09-12T20:14:14.483 回答
1

使用 a SocketChannel,您可以使用ByteBuffers 代替。

buffer.asIntBuffer().put(ints);
do {
  channel.write(buffer);
} while (buffer.hasRemaining());
于 2012-09-12T20:20:24.097 回答
1

如果 Java 代码需要有效地访问int[],那么很有可能使用套接字进行本机发送/接收是值得的。

但通常可以使用 IntBuffer 代替 int[]。在这种情况下,您可以分配一个 ByteBuffer 并从中获取一个 IntBuffer:

ByteBuffer bb = ByteBuffer.allocate(500000*4);
IntBuffer ib = bb.asIntBuffer();

您应该同时使用 allocate() 和 allocateDirect(),请参阅“ ByteBuffer.allocate() 与 ByteBuffer.allocateDirect() ”和http://objectissues.blogspot.co.il/2005/10/java-nio-allocate -vs-allocatedirect.html

重要的!在这种情况下,UnsupportedOperationException如果您尝试使用ib.array().

于 2012-09-13T10:49:41.170 回答