Почему я видел бы, что скорость на ~20% увеличивает использующий собственный код?

Если вы не можете принять какую-либо вероятность того, что sun.misc.Signal может измениться в недавнем будущем, просто реализуйте обработку сигнала самостоятельно, с помощью интерфейса JNI, на языке, который компилируется в машинный код (например, C), и импортируйте библиотеку с помощью System.load. Используя JNI, java может использовать C, а C может использовать java. В первый раз, когда я использовал JNI, мне показалось забавным иметь возможность использовать весь Java-API из моей C-программы.

Теперь единственное, о чем вам нужно беспокоиться, это изменится ли интерфейс ОС или, что более вероятно, изменится выбор используемой ОС.

24
задан Robert H. 20 May 2009 в 18:07
поделиться

7 ответов

Просто взглянув на этот код, я бы заподозрил по своему опыту довольно существенное замедление перехода от C ++ -> C #.

Одна серьезная проблема, с которой вы столкнетесь в наивном порте. подобной процедуры для C # состоит в том, что C # собирается добавить сюда проверку границ при каждой проверке массива. Так как вы никогда не перебираете массивы в цикле, который будет оптимизирован ( см. Этот вопрос для подробностей ), почти каждый доступ к массиву будет получать проверку границ.

Кроме того, этот порт довольно близок к отображению 1-> 1 из C.Если вы запустите это через хороший профилировщик .NET, вы, вероятно, найдете несколько отличных мест, которые можно оптимизировать, чтобы вернуть его к скорости, близкой к C ++, с помощью одной или двух настроек ( почти всегда я имел опыт переноса подобных подпрограмм).

Если вы хотите, чтобы это происходило с почти одинаковой скоростью, вам, вероятно, придется преобразовать это в небезопасный код и использовать манипуляции с указателями вместо непосредственной установки массивов. Это устранит все проблемы с проверкой границ и вернет вашу скорость.


Edit: Я вижу еще одно огромное различие, которое может быть причиной того, что ваш небезопасный код C # работает медленнее.

Посмотрите this страница о C # по сравнению с C ++ , в частности:

«Длинный тип: в C # длинный тип - это 64 бита, а в C ++ - 32 бита».

Вы должны преобразовать версию C # использовать int, не долго. В C # long - это 64-битный тип. На самом деле это может сильно повлиять на ваши манипуляции с указателем, потому что я считаю, что вы непреднамеренно добавляете преобразование long-> int (с проверкой переполнения) при каждом вызове указателя.

Кроме того, пока вы занимаетесь этим, вы можете попробовать обернуть всю функцию в неотмеченный блок . C ++ не выполняет проверку переполнения, которую вы выполняете в C #.

23
ответ дан 29 November 2019 в 00:01
поделиться

Это скорее всего, из-за того, что JIT-компилятор генерирует код, который не так эффективен, как код, сгенерированный собственным компилятором.

Профилирование кода, вероятно, должно быть вашим следующим шагом, если вас волнует снижение производительности на 20%, или вы можете рассмотреть возможность использования готовая оптимизированная библиотека.

3
ответ дан 29 November 2019 в 00:01
поделиться

Учитывая, что управляемый код выполняет проверку границ индекса каждого доступа к массиву, чего не делает неуправляемый код, я бы сказал, что разница меньше, чем я ожидал.

Если вы также измените массивы на указатели в управляемом коде (поскольку они действительно есть в неуправляемом коде), я бы ожидал, что они будут работать примерно так же.

1
ответ дан 29 November 2019 в 00:01
поделиться

Я просто запустил код, который он опубликовал, с int вместо long, и это не имело особого значения. Я знаю, что другим людям повезло больше с БПФ в .NET , показывающим, что .NET может достичь или превзойти уровень C ++ даже с математикой БПФ.

Итак, мой ответ: либо код постера более оптимизирован (для C), чем тот, который указан в ссылке, либо он менее оптимизирован для C #, чем тот, который в статье, на которую я ссылаюсь.

Я выполнил два набора тестов на двух машинах с .NET 2.0. Одна машина имела XPSP2 и единственный процессор Pentium III с тактовой частотой 850 МГц и 512 МБ оперативной памяти. Другая машина имела сборку Vista 5321 и однопроцессор Mobile Pentium 4 с тактовой частотой 2 ГГц и 1 ГБ оперативной памяти. В каждом случае я рассчитал среднее значение 100 отдельных вычислений БПФ для 217 (131072) значений данных. По этим значениям я рассчитал стандартную ошибку от стандартного отклонения.

Результаты отображаются в мс. Результаты для машины Pentium III:

  Не оптимизировано Оптимизировано для пространства Оптимизировано для скорости
Неуправляемый 92,88 ± 0,09 88,23 ± 0,09 68,48 ± 0,03
Управляемый C ++ 72,89 ± 0,03 72,26 ± 0,04 71,35 ± 0,06
C ++ / CLI 73,00 ± 0,05 72,32 ± 0,03 71,44 ± 0,04
C # Управляемый 72,21 ± 0,04 69,97 ± 0,08

Результаты для Mobile Pentium 4:

  Не оптимизировано Оптимизировано для пространства Оптимизировано для скорости
Неуправляемый 45,2 ± 0,1 30,04 ± 0,04 23,06 ± 0,04
Управляемый C ++ 23,5 ± 0,1 23,17 ± 0,08 23,36 ± 0,07
C ++ / CLI 23,5 ± 0,1 23,11 ± 0,07 23,80 ± 0,05
C # Управляемый 23,7 ± 0,1 22,78 ± 0,03
1
ответ дан 29 November 2019 в 00:01
поделиться

Вы использовали профилировщик, такой как AQTime , чтобы увидеть, где находится горлышко бутылки? Иногда при переводе нативного кода в управляемый возникает тривиальная задача. С другой стороны, поскольку управляемый код в некоторых сценариях работает медленнее, чем собственный код, вы можете вместо этого попробовать небезопасный код.

0
ответ дан 29 November 2019 в 00:01
поделиться

Собственный компилятор может выполнять гораздо более глубокую и тяжелую оптимизацию, чем JIT-компилятор, например векторизацию, межпроцедурный анализ и т. Д. А БПФ можно значительно ускорить с векторизацией.

3
ответ дан 29 November 2019 в 00:01
поделиться

Потому что компилятор C # .NET не самый лучший для создания эффективного кода. И этому мешает вся логика языка. Кстати, F # имеет гораздо лучшую производительность, чем C # в математике

0
ответ дан 29 November 2019 в 00:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: