У меня есть метод 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 # (вероятно, я не оптимизировал - предложения на этот счет также приветствуются). У меня вопрос: стоит ли мне переносить этот метод в неуправляемую DLL-библиотеку C? Будет ли результирующий метод выполняться быстрее (и насколько быстрее) с учетом издержек, связанных с маршалингом моего управляемого 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
), а второй массив расположен дробно относительно первого ( это означает, что вместо позиции, скажем, 10 относительно dest, она может быть позиционирована в 10.682791).
Для этого мне нужно интерполировать два значения в скобках в источнике (скажем, 10 и 11 в приведенном выше примере для первого элемента), а затем сравнить интерполированные байты с байтами назначения.
Я подозреваю, что умножение, включенное в эту функцию, значительно дороже, чем сравнение байтов, так что эта часть может быть красной сельдью (извините). Кроме того, даже если сравнения все еще несколько дороги относительно умножений, у меня все еще есть проблема, что эта система может фактически быть многомерной, что означает, что вместо сравнения одномерных массивов, массивы могут быть 2-, 5- или независимо от размеров, так что в конечном итоге время, затрачиваемое на вычисление интерполированных значений, будет меньше времени, затрачиваемого на окончательное байтовое сравнение 4 байтов (я полагаю, что это так).
Насколько дорого здесь умножение по сравнению со сдвигом битов, и может ли это быть той операцией, которую можно ускорить, выгружая в DLL C (или даже DLL сборки, хотя мне пришлось бы нанять кого-нибудь создать это для меня)?