Арифметика больших массивов в C#

Как лучше всего хранить 2D-массив в C#, чтобы оптимизировать производительность при выполнении большого количества арифметических операций с элементами в массиве?

У нас есть большие (примерно 1,5 ГБ) массивы, которые, например, мы хотим умножать друг на друга поэлементно. Производительность имеет решающее значение. Контекст, в котором это делается, находится в C#. Есть ли какой-нибудь умный способ хранить массивы и перебирать их? Можно ли написать эти части на неуправляемом C++ и действительно ли это повысит производительность? Массивы должны быть доступны для остальной части программы C#.

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

Эксперименты по времени показывают, что хранение и итерация данных в виде массива в C# медленнее, чем хранение в виде 2D-массива. Я хотел бы знать, есть ли еще лучший способ обработки данных. Конкретная выполненная арифметика не имеет отношения к вопросу.

Я не совсем понимаю, что вы имеете в виду, говоря о ваших экспериментах по таймингу. Вы имеете в виду, что массив C# 2D был медленнее, чем массив C 2D?

Cameron MacFarland 21.09.2008 18:17

Массив C# 2d был быстрее, чем массив 1d C#

AnnaR 21.09.2008 20:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
10
2
10 441
4

Ответы 4

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

Чтобы получить доступ к элементам массива как можно быстрее, вы можете использовать небезопасные указатели, например:

int[] array = Enumerable.Range(0, 1000).ToArray();

int count = 0;
unsafe {
    fixed (int* pArray = array) {
        for (int i = 0; i < array.Length; i++) {
            count += *(pArray + i);
        }
    }
}

РЕДАКТИРОВАТЬ Драт! Не заметил, что вы сказали 2D-массив. Этот трюк не сработает с многомерным массивом, поэтому я не уверен, насколько он поможет. Хотя вы можете превратить любой массив в одномерный массив, выполнив некоторую арифметику над индексом массива. Просто зависит от того, заботитесь ли вы о снижении производительности при индексировании массива или при итерации по массиву.

@Cameron MacFarland: на самом деле он может работать для 2D-массивов, вам просто нужно сделать что-то вроде * (pArray + (ii * cols) + jj).

user7116 21.09.2008 17:53

sixlettervariables: полезно знать. Хотя это применимо только к прямоугольным массивам [,], а не к массивам с зазубринами [] [], если вы не используете счетчик столбцов для текущего массива, что замедлит работу.

Cameron MacFarland 21.09.2008 18:02

Предлагаю измерить, измерить и ... хотя бы измерить! Даже если арифметика с указателями действительно приносила значительный прирост производительности в более ранних версиях JIT, оптимизация все же значительно продвинулась. К настоящему времени (.NET 4.0) преимущество кажется почти незначительным.

user492238 16.04.2011 21:26

Анна,

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

http://msdn.microsoft.com/en-us/magazine/cc163995.aspx

Согласно статье C#, при использовании прямоугольных массивов (2d) может быть очень хорошим исполнителем. Вот график, который показывает разницу в производительности между зубчатыми массивами (массив массивов) и прямоугольными массивами (многомерными) массивами.

альтернативный текст http://i.msdn.microsoft.com/cc163995.fig08.gif

Я бы предложил поэкспериментировать и использовать для сравнения анализ производительности в VS 2008.

Если использование C# «достаточно быстрое», ваше приложение будет намного проще поддерживать.

Удачи!

Результаты, показанные на этом графике, взяты из .Net 1.1. Зубчатые массивы на самом деле быстрее многомерных массивов в .Net 3 и 4, как показано здесь: codeproject.com/KB/cross-platform/BenchmarkCppVsDotNet.aspx

AndrewS 15.09.2011 16:07

@AndrewS - .Net 4 не был выпущен, когда я ответил на этот вопрос еще в 2008 году.

Jason Stevenson 16.09.2011 23:26

Если вы загружаете F# и ссылаетесь на одну из библиотек времени выполнения (я думаю, что это FSharp.PowerPack) и используете Microsoft.FSharp.Maths.Matrix. Он оптимизируется в зависимости от того, используете ли вы плотную или разреженную матрицу.

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

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

Довольно простой способ сделать это - написать небольшую функцию доступа, чтобы превратить ваши индексы строки / столбца в индекс и работать с одномерной матрицей, дружественным к кешу способом.

Функция должна группировать близлежащие координаты в близлежащие индексы. Мортон-ордер можно использовать, если вы работаете на мощности двух размеров. Для размеров без мощности часто можно привести только 4 младших бита в порядок Мортона и использовать обычную арифметику индексов для старших битов. Вы все равно получите значительное ускорение, даже если преобразование координат в индекс кажется дорогостоящей операцией.

http://en.wikipedia.org/wiki/Z-order_(curve) <- извините, не могу указать, что SO не любит URL-адреса с тире в нем. Вы должны вырезать и пасту.

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

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