【发布时间】:2010-05-30 13:15:13
【问题描述】:
我有这个 C# 方法,我正在尝试优化:
// 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 数组。对于每对匹配元素,该方法比较每个单独的字节值并取两者中的较大者。然后为第一个数组中的元素分配一个新的int 值,该值由 4 个最大字节值构成(与来源无关)。
我认为我已经在 C# 中尽可能地优化了这个方法(当然,我可能没有 - 也欢迎关于这个分数的建议)。我的问题是,将这个方法移动到非托管 C DLL 对我来说值得吗? 考虑到编组托管 @ 的开销,生成的方法会执行得更快(以及快多少) 987654324@ 数组,以便可以将它们传递给方法?
如果这样做能让我的速度提高 10%,那么肯定不值得我花时间。如果它快 2 或 3 倍,那么我可能不得不这样做。
注意:请不要“过早优化”cmets,在此先感谢。这只是简单的“优化”。
更新:我意识到我的代码示例没有捕捉到我在这个函数中尝试做的所有事情,所以这里是一个更新版本:
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),并且第二个数组的位置相对于第一个 (这意味着它可以定位在 10.682791),而不是相对于 dest 的 10)。
为了实现这一点,我必须在源中的两个括号值之间进行插值(例如,上例中的 10 和 11,对于第一个元素),然后将插值字节与目标字节进行比较。
我在这里怀疑这个函数中涉及的乘法比字节比较的成本要高得多,所以这部分可能是一个红鲱鱼(对不起)。此外,即使比较相对于乘法来说仍然有些昂贵,我仍然有这个系统实际上可以是多维的问题,这意味着不是比较一维数组,而是数组可以是 2-、5- 或任何维度,因此最终计算插值所花费的时间将使最终按字节比较 4 个字节所花费的时间相形见绌(我假设是这种情况)。
相对于位移位,这里的乘法有多昂贵,这种操作是否可以通过卸载到 C DLL(甚至是程序集 DLL,尽管我不得不雇人)来加速为我创建)?
【问题讨论】:
-
顺便说一句,我很好奇您使用此算法的目的。愿意启发我们吗?
-
这是遗传算法的事情。每个数组代表一个伪染色体,这个合并过程需要任一染色体中最大的字节来产生表型输出。
-
在您的编辑中小题大做:您不能用
rem = pos%1;替换rem = pos - Math.Floor(pos);吗?它不会快一个数量级,但如果你足够频繁地调用该函数,它可能会有所不同。 -
@Drew:数组通常有大约 10,000 个元素(src)和至少 75,000 个(dest),所以这将是一个很小的改进,除非
Math非常慢(我从不使用 @ 987654331@ 无论如何都在一个昂贵的循环中)。
标签: c# c optimization assembly