Скорость сортировки .NET
-
19-08-2019 - |
Вопрос
У меня есть подпись метода C ++, которая выглядит следующим образом:
static extern void ImageProcessing(
[MarshalAs(UnmanagedType.LPArray)]ushort[] inImage,
[MarshalAs(UnmanagedType.LPArray)]ushort[] outImage,
int inYSize, int inXSize);
Я обернул функцию в методы синхронизации, как внутренние, так и внешние. Внутренне, функция работает на 0,24 с. Внешне функция работает за 2,8 с, или примерно в 12 раз медленнее. В чем дело? Маршаллинг замедляет меня так сильно? Если это так, как я могу обойти это? Должен ли я перейти на небезопасный код и использовать указатели или что-то? Я в некотором замешательстве относительно того, откуда взялись дополнительные затраты времени.
Решение 3
Ответ, к сожалению, гораздо более приземленный, чем эти предложения, хотя они и помогают. По сути, я перепутал с тем, как у меня шли сроки.
Временной код, который я использовал, был следующим:
Ipp32s timer;
ippGetCpuFreqMhz(&timer);
Ipp64u globalStart = ippGetCpuClocks();
globalStart = ippGetCpuClocks() *2 - globalStart; //use this method to get rid of the overhead of getting clock ticks
//do some stuff
Ipp64u globalEnd = ippGetCpuClocks();
globalEnd = ippGetCpuClocks() *2 - globalEnd;
std::cout << "total runtime: " << ((Ipp64f)globalEnd - (Ipp64f)globalStart)/((Ipp64f)timer *1000000.0f) << " seconds" << std::endl;
Этот код специфичен для компилятора Intel и разработан для обеспечения чрезвычайно точных измерений времени. К сожалению, такая предельная точность означает стоимость примерно 2,5 секунды на цикл Удаление временного кода сняло это временное ограничение.
Тем не менее, кажется, что время выполнения все еще задерживается - код сообщит о 0,24 с при включенном временном коде, и теперь сообщает о времени примерно 0,35 с, что означает, что скорость составляет около 50%. Р>
Изменение кода на это:
static extern void ImageProcessing(
IntPtr inImage, //[MarshalAs(UnmanagedType.LPArray)]ushort[] inImage,
IntPtr outImage, //[MarshalAs(UnmanagedType.LPArray)]ushort[] outImage,
int inYSize, int inXSize);
и называется как:
unsafe {
fixed (ushort* inImagePtr = theInputImage.DataArray){
fixed (ushort* outImagePtr = theResult){
ImageProcessing((IntPtr)inImagePtr,//theInputImage.DataArray,
(IntPtr)outImagePtr,//theResult,
ysize,
xsize);
}
}
}
сокращает время выполнения до 0,3 с (в среднем три запуска). Все еще слишком медленный для моих вкусов, но повышение скорости в 10 раз, безусловно, в рамках приемлемости для моего босса.
Другие советы
Посмотрите на эта статья . Хотя основное внимание уделяется Compact Framework, общие принципы применимы и к рабочему столу. Соответствующая цитата из раздела анализа выглядит следующим образом:
Управляемый вызов напрямую не вызывает собственный метод. Вместо этого он вызывает метод-заглушку JITted, который должен выполнять некоторые служебные процедуры, такие как вызовы, для определения статуса выгрузки GC (чтобы определить, ожидает ли GC, и нам нужно подождать). Также возможно, что некоторый код маршаллинга также получит JITted в заглушку. Это все требует времени.
Изменить . Также стоит прочитать эту статью блога о совершенстве кода JITted - опять же, специфично для CF, но все еще актуально Также есть статья, в которой рассматривается глубина стека вызовов и ее влияние на производительность , хотя этот, вероятно, специфичен для CF (не тестируется на рабочем столе).
Вы пытались переключить два параметра массива на IntPtr? PInvoke работает максимально быстро, когда все типы в маршалинговой сигнатуре являются легковесными. Это означает, что Pinvoke сводится к простой memcpy для получения данных взад и вперед. Р>
В моей команде мы нашли самый эффективный способ управления нашим слоем PInvoke -
<Ол>Как и в случае с любым "!", это будет быстрее &. ответ, вам нужно профилировать это ваша собственная база кода. Мы пришли к этому решению только после того, как несколько методов были рассмотрены и представлены. Р>