我有两个长字节数组,我需要计算相应位置上的字节数是否相同。我的解决方案(在JAVA中)如下:
int sum = 0;
for(int i = 0;i < t.length;i++)
if (t[i] == spb[i])
sum++;
由于我的程序的这部分花费了大量时间,我想知道我是否可以更快地完成这个任务
显然两个数组的长度相同
答案 0 :(得分:6)
如果数组很长,你可以使用多个并发线程来计算数组部分的部分和,然后总结部分总和。
答案 1 :(得分:5)
不,你基本上做的是正确的事情(至少对于一个线程来说 - 西蒙的使用多线程的想法很好)。这需要多长时间,阵列有多长?它应该很快。
你可能能够通过在字节数组周围创建ByteBuffer
来加速它,然后使用asLongBuffer
创建一个LongBuffer
再次包装它。然后,您可以一次检查8个字节(如长),仅在long
比较返回false时检查单个字节。这会是一个非常复杂的代码 - 而且我不会在所有中惊讶地发现它实际上要慢得多。
答案 2 :(得分:1)
除了使用先前建议的“并发线程来计算数组部分的部分和”方法之外(我将在后面的段落中进行评论),您可以使用两种简单的技术来加速循环:(1){ {1}}三级运算符而不是?:
测试,以及(2)循环展开。
在我的旧2GHz系统上,使用gcj java编译器,每种技术都提供了几个百分点的加速。您在机器上获得的改进(如果有的话)可能是编译器或jvm相关的。
代码示例:
if
转到
if (t[i] == spb[i]) sum++;
和
sum += t[i] == spb[i] ? 1 : 0;
转到(例如)
public static int counts (byte[] A, byte[] B) {
int i, count, L=A.length;
for (count=i=0; i<L; i++)
count += A[i]==B[i] ? 1 : 0;
return count;
}
循环展开可以使用 public static int counts (byte[] A, byte[] B) {
final int S=8;
int i, count, L=A.length-S;
for(count=i=0; i<L; i+=S) {
count += A[i+0]==B[i+0] ? 1 : 0;
count += A[i+1]==B[i+1] ? 1 : 0;
count += A[i+2]==B[i+2] ? 1 : 0;
count += A[i+3]==B[i+3] ? 1 : 0;
count += A[i+4]==B[i+4] ? 1 : 0;
count += A[i+5]==B[i+5] ? 1 : 0;
count += A[i+6]==B[i+6] ? 1 : 0;
count += A[i+7]==B[i+7] ? 1 : 0;
}
for (; i<L+S; ++i)
count += A[i]==B[i] ? 1 : 0;
return count;
}
,其值大于或小于上面显示的S
。但是,在我运行的测试中,S=8
与S=16
相比几乎没有任何改进。一些采样时序,202MB阵列:
S=8
在此次运行中,E。时间比A小6%,而F.和G.比E小8%,比A小14%。(其他时间,未显示,验证前一个回答声称“请求对象的字段(t.length)比局部变量花费更多的时间”,这是无关紧要的。)
关于并发线程的使用:假设您使用三个线程。在其他方法中,您可以让线程A. 51094384 matches in 3.421857144 sec. (original loop)
E. 51094384 matches in 3.212364808 sec. (use ?: value)
F. 51094384 matches in 2.953596272 sec. (?: + S=8 unroll)
G. 51094384 matches in 2.949984214 sec. (?: + S=16 unroll)
处理每个数组的i
'三分之一中的连续字节,或者您可以让线程i
处理每个第三个字节,即带有字节的字节index mod 3 = i
。值得对执行时间的差异进行基准测试。我希望它在不同的机器上会有所不同,具体取决于缓存大小和制度。
答案 3 :(得分:0)
int sum = 0;
for(int i = t.length - 1;i >= 0 ;i--)
if (t[i] == spb[i])
sum++;
原则上,请求对象的字段(t.length)比局部变量(i)花费更多的时间。如果从最后一个迭代到第一个,那么最昂贵的指令只执行一次。