Почему матричное умножение в .NET так медленно?

Я не совсем понимаю, что делает матричное умножение в С#/.NET(и даже Java) настолько медленным.

Взгляните на этот тест (источник): Попытка найти обновленный ориентир.

Java vs С# vs С++ breakdown http://img411.imageshack.us/img411/9324/perf.gif

Ц # целое число и двойная производительность прокляты близко к С++, скомпилированному с MSVС++. 87% так же быстро и вдвое быстрее и на 99% для 32-битного целого. Я бы сказал, довольно хорошо. Но тогда посмотрим на матричное умножение. Разрыв расширяется до С#, составляющего примерно 19%. Это довольно большое несоответствие, которое я не понимаю. Матричное умножение - всего лишь куча простой математики. Как это происходит так медленно? Разве это не должно быть примерно так же быстро, как эквивалентное число простых операций с плавающей запятой или целым числом?

Это особенно касается игр и XNA, где матрица и векторная производительность имеют решающее значение для таких вещей, как физические движки. Некоторое время назад Моно добавила поддержку инструкций SIMD через отличные векторные и матричные классы. Он закрывает пробел и делает Mono быстрее, чем написанный вручную С++, хотя и не такой быстрый, как С++ с SIMD. (источник)

Сравнение умножения матрицы http://img237.imageshack.us/img237/2788/resultse.png

Что здесь происходит?

Изменить: Присматриваясь, я неправильно читаю второй график. С# выглядит довольно близко. Является ли первый тест просто чем-то ужасным? Извините, я пропустил номер версии в первом тесте. Я схватил его за удобную ссылку, потому что "линейная алгебра С# медленна", которую я всегда слышал. Я попытаюсь найти другую.

Ответы

Ответ 1

С такими крупными матрицами кеш процессора становится ограничивающим фактором. Что важно, как хранить матрицу. И контрольный код сравнивает яблоки и апельсины. Код С++ использовал неровные массивы, код С# использует двумерные массивы.

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

Ответ 2

Чтобы объяснить происхождение идеи о том, что операции матрицы XNA медленны:

Прежде всего, есть начальный уровень: XNA Matrix class operator* сделает несколько копий. Это медленнее, чем вы ожидаете от эквивалентного кода на С++.

(Конечно, если вы используете Matrix.Multiply(), вы можете пройти по ссылке.)

Вторая причина заключается в том, что .NET Compact Framework, используемая XNA на Xbox 360, не имеет доступа к оборудованию VMX (SIMD), доступному для родных игр на С++.

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

Ответ 3

Хорошо, что контрольный автор не понимал разницы между зубчатыми и многомерными массивами в С#. Это было не сравнение яблок с яблоками. Когда я изменил код, чтобы использовать неровные массивы вместо многомерных массивов, так что он работает более похожим на Java, тогда код С# заканчивается в два раза быстрее... делая его быстрее, чем Java (хотя это едва ли возможно, и это возможно статистически незначителен). В С# многомерные массивы медленнее, потому что есть дополнительная работа по поиску слота массива и потому, что проверка границ массива не может быть устранена для них... пока.

Смотрите question для более глубокого анализа того, почему многомерные массивы медленнее, чем зубчатые массивы.

См. blog для получения дополнительной информации о проверке границ массива. В статье специально предостерегает от использования многомерных массивов для матричного умножения.

Ответ 4

Здесь приведен обновленный тест, посвященный матричной мультипсии (и некоторым эталонам с использованием новой параллельной библиотеки задач):

Умножение параллельной матрицы с параллельной библиотекой задач (TPL)

Статья посвящена различным методам и объясняет, почему многомерные массивы являются плохим выбором:

Самый простой способ сделать матрицу умножение с .NET. многомерный массив с i, j, k упорядочение в петлях. Проблемы являются двоякими. Во-первых, упорядочение i, j.k беспрепятственный доступ к памяти в результате чего данные в разных местах будут втянул. Во-вторых, он использует многомерный массив. Да,.NET. многомерный массив удобен, но он очень медленный.