// assume arrays are same dimensions private void DoSomething(int[] bigArray1,int[] bigArray2) { int data1; byte A1,B1,C1,D1; int data2; byte A2,B2,C2,D2; for (int i = 0; i < bigArray1.Length; i++) { data1 = bigArray1[i]; data2 = bigArray2[i]; A1 = (byte)(data1 >> 0); B1 = (byte)(data1 >> 8); C1 = (byte)(data1 >> 16); D1 = (byte)(data1 >> 24); A2 = (byte)(data2 >> 0); B2 = (byte)(data2 >> 8); C2 = (byte)(data2 >> 16); D2 = (byte)(data2 >> 24); A1 = A1 > A2 ? A1 : A2; B1 = B1 > B2 ? B1 : B2; C1 = C1 > C2 ? C1 : C2; D1 = D1 > D2 ? D1 : D2; bigArray1[i] = (A1 << 0) | (B1 << 8) | (C1 << 16) | (D1 << 24); } }
该函数基本上比较了两个int数组.对于每对匹配元素,该方法对每个单独的字节值进行比较,并取得两者中较大者.然后,第一个数组中的元素被分配一个从4个最大字节值构造的新的int值(不考虑源).
我想我已经在C#中尽可能的优化了这个方法(当然我也没有,对这个分数的建议也是可以接受的).我的问题是,是否值得我将此方法转移到非托管C DLL?考虑到编组我的托管int数组的开销,所得到的方法执行速度会更快(并且速度更快),以便将它们传递给方法?
如果这样做会让我,比如提高10%的速度,那么我的时间肯定不值得.如果速度是2或3倍,那么我可能要这样做.
注意:请不要“过早优化”评论,提前感谢.这只是“优化”.
更新:我意识到我的代码示例没有捕获我在这个函数中尝试做的一切,所以这里是一个更新的版本:
private void DoSomethingElse(int[] dest,int[] src,double pos,double srcMultiplier) { int rdr; byte destA,destB,destC,destD; double rem = pos - Math.Floor(pos); double recipRem = 1.0 - rem; byte srcA1,srcA2,srcB1,srcB2,srcC1,srcC2,srcD1,srcD2; for (int i = 0; i < src.Length; i++) { // get destination values rdr = dest[(int)pos + i]; destA = (byte)(rdr >> 0); destB = (byte)(rdr >> 8); destC = (byte)(rdr >> 16); destD = (byte)(rdr >> 24); // get bracketing source values rdr = src[i]; srcA1 = (byte)(rdr >> 0); srcB1 = (byte)(rdr >> 8); srcC1 = (byte)(rdr >> 16); srcD1 = (byte)(rdr >> 24); rdr = src[i + 1]; srcA2 = (byte)(rdr >> 0); srcB2 = (byte)(rdr >> 8); srcC2 = (byte)(rdr >> 16); srcD2 = (byte)(rdr >> 24); // interpolate (simple linear) and multiply srcA1 = (byte)(((double)srcA1 * recipRem) + ((double)srcA2 * rem) * srcMultiplier); srcB1 = (byte)(((double)srcB1 * recipRem) + ((double)srcB2 * rem) * srcMultiplier); srcC1 = (byte)(((double)srcC1 * recipRem) + ((double)srcC2 * rem) * srcMultiplier); srcD1 = (byte)(((double)srcD1 * recipRem) + ((double)srcD2 * rem) * srcMultiplier); // bytewise best-of destA = srcA1 > destA ? srcA1 : destA; destB = srcB1 > destB ? srcB1 : destB; destC = srcC1 > destC ? srcC1 : destC; destD = srcD1 > destD ? srcD1 : destD; // convert bytes back to int dest[i] = (destA << 0) | (destB << 8) | (destC << 16) | (destD << 24); } }
本质上这与第一种方法是一样的,除了在第一种方法之外,第二个数组(src)总是小于第一个(dest),而第二个数组相对于第一个数组(即不是位于,比如说相对于dest,10可以定位在10.682791).
为了实现这一点,我必须在源中的两个包围值之间进行内插(例如,在上面的例子中为10和11,对于第一个元素),然后将插入的字节与目标字节进行比较.
我怀疑这个函数所涉及的乘法比字节比较成本要高得多,所以这部分可能是一个红色的鲱鱼(对不起).此外,即使比较相对于乘法仍然有些昂贵,我仍然有这个问题,即该系统实际上可以是多维的,这意味着不是比较一维阵列,阵列可以是2-,5-或所以最终计算内插值所花费的时间将缩短4个字节的最后一个字节比较所花费的时间(我假设是这种情况).
这里的乘法相对于位移有多贵,而且这种操作可以通过卸载到C DLL(甚至是一个程序集DLL)来加速,尽管我必须聘请有人来创建为了我)?
解决方法
private static void DoOtherThing(int[] bigArray1,int[] bigArray2) { unsafe { fixed (int* p1 = bigArray1,p2=bigArray2) { byte* b1 = (byte*)p1; byte* b2 = (byte*)p2; byte* bend = (byte*)(&p1[bigArray1.Length]); while (b1 < bend) { if (*b1 < *b2) { *b1 = *b2; } ++b1; ++b2; } } } }
在我的机器上,在版本模式下运行的调试器与2500万个int数组相比,这个代码比原来的快29%.但是,独立运行时,运行时几乎没有区别.有时你的原始代码更快,有时新的代码更快.
大概数字:
Debugger Standalone Original 1,400 ms 700 ms My code 975 ms 700 ms
而且,是的,我做了比较结果,以确保功能做同样的事情.
我很遗憾的解释为什么我的代码不是更快,因为它的工作明显减少了.
鉴于这些结果,我怀疑您可以通过转到本地代码来改善事情.正如你所说,编组阵列的开销可能会减少您在处理中可能会实现的任何节省.
private static void DoSomething(int[] bigArray1,int[] bigArray2) { for (int i = 0; i < bigArray1.Length; i++) { var data1 = (uint)bigArray1[i]; var data2 = (uint)bigArray2[i]; var A1 = data1 & 0xff; var B1 = data1 & 0xff00; var C1 = data1 & 0xff0000; var D1 = data1 & 0xff000000; var A2 = data2 & 0xff; var B2 = data2 & 0xff00; var C2 = data2 & 0xff0000; var D2 = data2 & 0xff000000; if (A2 > A1) A1 = A2; if (B2 > B1) B1 = B2; if (C2 > C1) C1 = C2; if (D2 > D1) D1 = D2; bigArray1[i] = (int)(A1 | B1 | C1 | D1); } }