Вопрос

По моему опыту, .NET в 2–3 раза медленнее, чем собственный код.(Я применил L-BFGS для многомерной оптимизации).

Я проследил рекламу в stackoverflow доhttp://www.centerspace.net/products/

скорость действительно потрясающая, скорость близка к нативному коду.Как они могут это сделать?Они сказали, что:

К.Является ли NMath «чистым» .NET?

А.Ответ в некоторой степени зависит от вашего определения «чистого .NET».NMath написан на C# плюс небольшой уровень Managed C++.Однако для повышения производительности базовых операций линейной алгебры NMath использует собственную библиотеку ядра Intel Math (входит в состав NMath).Но здесь нет ни COM-компонентов, ни DLL — только сборки .NET.Кроме того, вся память, выделенная на уровне управляемого C++ и используемая собственным кодом, выделяется из управляемой кучи.

Может ли кто-нибудь объяснить мне больше?

Это было полезно?

Решение

Вопрос о C++/CLI верен.Для полноты картины еще два интересных момента:

  • Управление памятью .NET (сборщик мусора), очевидно, не является проблемой здесь, поскольку NMath все еще зависит от него.

  • Преимущество в производительности фактически обеспечивается Intel MKL, которая предлагает реализации, чрезвычайно оптимизированные для многих процессоров.С моей точки зрения, это решающий момент.Использование простого и наивного кода C/C++ не обязательно обеспечит более высокую производительность по сравнению с C#/.NET, а иногда даже хуже.Однако C++/CLI позволяет использовать все «грязные» варианты оптимизации.

Другие советы

Как они могут это сделать?

Как и большинство числовых библиотек для .NET, NMath представляет собой не более чем оболочку Intel MKL, встроенного в сборку .NET, вероятно, путем связывания с C++/CLI для создания смешанная сборка.Вероятно, вы только что протестировали те фрагменты, которые на самом деле не написаны в .NET.

Статьи журнала F#.NET Числовые библиотеки:специальные функции, интерполяция и случайные числа (16 марта 2008 г.) и Числовые библиотеки:линейная алгебра и спектральные методы (16 апреля 2008 г.) протестировал немало функциональных возможностей, и NMath оказалась самой медленной из всех коммерческих библиотек.Их PRNG был медленнее всех остальных и на 50 % медленнее, чем бесплатная библиотека Math.NET, отсутствовали некоторые базовые функции (например,умение рассчитывать Gamma(-0.5)) и другие базовые функции (функции, связанные с Gamma), которые они предоставляли, были сломаны.И Extreme Optimization, и Bluebit превзошли NMath в тесте собственного решателя.В то время NMath даже не предоставлял преобразования Фурье.

Еще более удивительно то, что расхождения в производительности иногда были огромными.Самая дорогая протестированная нами коммерческая числовая библиотека (IMSL) была более чем в 500 раз медленнее, чем бесплатная библиотека FFTW в тесте FFT и никто библиотек в то время использовали несколько ядер.

Фактически, именно низкое качество этих библиотек побудило нас коммерциализировать наши собственные F# для числовых значений библиотеку (которая представляет собой 100% чистый код F#).

Я один из ведущих разработчиков ILЦифровые значения.Так что я, очевидно, предвзят ;) Но мы более раскрыты в отношении наших внутренних качеств, поэтому я дам некоторое представление о наш «секреты» скорости.

Все зависит от того, как используются системные ресурсы!Если вам нужна чистая скорость и вам нужно обрабатывать большие массивы, вы обязательно (в порядке важности, самое важное сначала)

  1. Управляйте своей памятью правильно!«Наивное» управление памятью приведет к снижению производительности, поскольку оно сильно нагружает сборщик мусора, вызывает фрагментацию памяти и ухудшает локальность памяти (следовательно, производительность кэша).В среде сбора мусора, такой как .NET, это сводится к предотвращению частого выделения памяти.Для достижения этой цели в ILNumerics мы реализовали высокопроизводительный пул памяти (и детерминированное удаление временных массивов для получения красивого и удобного синтаксиса без неуклюжей семантики функций).

  2. Используйте параллелизм!Это нацелено на оба:параллелизм на уровне потоков и параллелизм на уровне данных.Несколько ядер используются для потоковой обработки частей вычислений, требующих большого объема вычислений.На процессорах X86/X64 расширения SIMD/мультимедиа, такие как SSE.XX и AVX, позволяют выполнять небольшую, но эффективную векторизацию.Они не доступны напрямую в современных языках .NET.И это единственная причина, по которой MKL может работать быстрее, чем «чистый» код .NET.(Но решения уже появляются.)

  3. Для архивирования скорость высокооптимизированных языков как и в FORTRAN и C++, к вашему коду должны быть применены те же оптимизации, что и для них.C# предлагает такую ​​возможность.

Обратите внимание: эти меры предосторожности следует соблюдать именно в таком порядке!Нет смысла заботиться о расширениях SSE или даже об удалении связанных проверок, если узким местом является полоса пропускания памяти, а процессор(ы) проводят большую часть времени в ожидании новых данных.Кроме того, для многих простых операций даже не стоит тратить огромные усилия на достижение максимальной производительности в самом крошечном масштабе!Рассмотрим распространенный пример функции LAPACK DAXPY.Он добавляет элементы вектора X к соответствующему элементу другого вектора Y.Если это делается впервые, всю память для X и Y придется извлечь из основной памяти.Вы практически ничего не можете с этим поделать.И память является узким местом!Итак, независимо от того, выполнено ли добавление в конце наивным способом в C #

for (int i = 0; i < C.Length; i++) {
    C[i] = X[i] + Y[i]; 
}

или сделать это с помощью стратегий векторизации — придется дождаться памяти!

Я знаю, что этот ответ каким-то образом «переоценивает» вопрос, поскольку большинство этих стратегий в настоящее время не используются в упомянутом продукте (пока?).Следуя этим пунктам, вы в конечном итоге получите гораздо лучшую производительность, чем любая наивная реализация на «родном» языке.

Если вам интересно, вы могли бы раскрыть свою реализацию L-BFGS?Я буду рад преобразовать его в ILNumerics и опубликовать результаты сравнения, и я уверен, что другие библиотеки, перечисленные здесь, захотят последовать моему примеру.(?)

Я разместил блог статья обращаясь к этому вопросу.

Ключ С++/CLI.Он позволяет компилировать код C++ в управляемую сборку .NET.

Сегодня отраслевым стандартом является создание смешанных .Net/родных библиотек, чтобы использовать преимущества обеих платформ для оптимизации производительности.Не только NMath, многие коммерческие и бесплатные библиотеки с интерфейсом .net работают так.Например:числовые значения Math.NET, днАналитика, Экстремальная оптимизация, ФинМатематика и многие другие.Интеграция с MKL чрезвычайно популярна для числовых библиотек .net, и большинство из них просто используют управляемую сборку C++ в качестве промежуточного уровня.Но такое решение имеет ряд недостатков:

  1. Intel MKL — это проприетарное программное обеспечение, и оно немного дороже.Но некоторые библиотеки, такие как dnAnalytics, предоставляют бесплатную замену функциональности MKL чистым кодом .net.Конечно, это намного медленнее, но зато бесплатно и полностью функционально.

  2. Это снижает вашу совместимость: вам нужны тяжелые управляемые библиотеки DLL ядра C++ как для 32-битного, так и для 64-битного режима.

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

Последние две задачи решены в библиотеке RTMath FinMath.Я действительно не знаю, как они это сделали, но они предоставляют одну чистую .net dll, которая скомпилирована для любой платформы ЦП и поддерживает 32-битные и 64-битные версии.Также я не заметил никакого снижения производительности по сравнению с MKL, когда мне нужно вызвать NormalCDF миллиарды раз.

Поскольку (родной) Intel MKL выполняет математические операции, вы фактически не выполняете математические операции в управляемом коде.Вы просто используете диспетчер памяти из .Net, поэтому результаты легко используются кодом .Net.

Я узнал больше из комментария @Darin Dimitrov к его ответу и комментария @Trevor Misfeldt к комментарию @Darin.Поэтому публикую это как ответ для будущих читателей.

NMath использует P/Invoke или C++/CLI для вызова собственных функций библиотеки ядра Intel Math, где выполняются наиболее интенсивные вычисления и поэтому это происходит так быстро.

А время потрачено в методы декомпозиции внутри Intel MKL. Копирование данных не требуется., или.Так, дело не в том, быстрый ли CLI или нет. Речь идет о том, где происходит казнь.

Также полезно читать блог @Paul.Вот резюме.

C# — быстрый, а распределение памяти — нет. Повторно используйте переменные в качестве параметров ref или out., вместо возврата новых переменных из методов.Выделение новой переменной потребляет память и замедляет выполнение.@Haymo Kutschbach хорошо это объяснил.

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

Для многих коротких вычислений вызвать подпрограмму C++/cli из C#, закрепить все указатели на данные, выделенные в управляемом пространстве, а затем вызвать библиотеку Intel, как правило, лучше, чем использовать P/Invoke для вызова библиотеки непосредственно из C#, поскольку стоимость маршалирования данных.Как упоминал @Haymo Kutschbach в комментариях, для преобразуемых типов нет разницы между C++/CLI и C#.Массивы преобразуемых типов и классов, которые содержат только преобразуемые элементы, во время маршалинга закрепляются, а не копируются.Ссылаться https://msdn.microsoft.com/en-us/library/75dwhxf7(v=vs.110).aspx для списка преобразуемых и непреобразуемых типов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top