Производительность 2-мерного массива по сравнению с 1-мерным массивом - PullRequest
38 голосов
/ 07 августа 2009

Есть ли в C разница во времени и пространстве между двумерным массивом m × n и одномерным массивом длины m × n (для больших значений m и n)? Будет ли доступ к элементам быстрее с 1-мерным массивом?

Ответы [ 6 ]

40 голосов
/ 07 августа 2009

В C 2-мерные массивы - это просто аккуратная схема индексации для 1-мерных массивов. Как и в случае с одномерным массивом, двумерные массивы выделяют один блок непрерывной памяти, а запись A[row][col] аналогична высказыванию A[row*NCOLS+col].

Обычно, если бы вы реализовали свои собственные многомерные массивы с использованием одномерных массивов, вы бы написали функцию индексации:

int getIndex(int row, int col) { return row*NCOLS+col; }

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

Для иллюстрации:

#define NROWS 10
#define NCOLS 20

Это:

int main(int argc, char *argv[]) {
    int myArr[NROWS*NCOLS];
    for (int i=0; i<NROWS; ++i) {
       for (int j=0; j<NCOLS; ++j) {
          myArr[getIndex(i,j)] = i+j;
       }
    }
    return 0;
}

Должен работать так же, как это:

int main(int argc, char *argv[]) {
    int myArr[NROWS][NCOLS];
    for (int i=0; i<NROWS; ++i) {
       for (int j=0; j<NCOLS; ++j) {
          myArr[i][j] = i+j;
       }
    }
    return 0;
}

Хотя, как AraK указал , если вы много перепрыгиваете по строкам, а строки очень большие, вы можете столкнуться с большим количеством ошибок страниц ... в этом В этом случае может помочь пользовательская индексная функция (с переключенными строками и столбцами), но может просто изменить, какое из измерений в двумерном массиве вы рассматриваете как строки, а какие - как столбцы.

8 голосов
/ 07 августа 2009

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

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

Посмотрите на эту статью в Википедии, если хотите сделать построчное отображение . Ваше отображение может быть столбцовым, например, матрицы FORTRAN.

3 голосов
/ 07 августа 2009

Роберт прав. Индексные выражения компилируются в арифметические выражения-указатели, поэтому нет никакой разницы.

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

На современных процессорах доступ к большим массивам с разной скоростью может привести к неожиданным различиям в производительности. Последовательный доступ всегда самый быстрый, а другие шаги могут быть в 30 раз медленнее из-за взаимодействия с кешем. Многомерные массивы, в которых внутренние измерения имеют степень двойки, часто имеют низкую производительность из-за того, как они взаимодействуют с ассоциативностью кэша. Чтобы понять эти проблемы, нет реальной замены для измерения.

3 голосов
/ 07 августа 2009

Не думаю, что есть какая-то разница. Внутренне c обрабатывает двумерный массив как несколько последовательных одномерных массивов.

Однако, как и во всех других случаях, ваш пробег может отличаться. Там может быть какая-то тонкая арифметическая разница указателя. Запустите синхронизированные тесты в обоих сценариях. Тот, кто бежит быстрее, побеждает.

2 голосов
/ 07 августа 2009

Как говорят другие, разница действительно в том, как вы получаете доступ к своим элементам: какое значение имеет то, как ваши элементы располагаются в памяти, которая является линейной, по крайней мере, на общих архитектурах. Таким образом, все, что у вас есть на самом деле, это 1d массив, 2d и т. Д. - это «просто» удобство, и разумный компилятор должен оптимизировать индексацию - но на практике, когда у вас больше нескольких переменных, компиляторы часто терпят неудачу на arch как х86 из-за голодания регистра.

Теперь это зависит от вашего приложения, но я думаю, что вы должны подумать о 1d макете по умолчанию, особенно если вам нужно обрабатывать несколько измерений. Первая проблема с многомерными массивами в C состоит в том, что вы не можете динамически распределять их - если вы выделяете для каждой строки, вы будете иметь ужасную производительность, потому что у вас нет смежной части памяти. Подробнее об этом см. FFTW doc .

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

0 голосов
/ 07 августа 2009

Я только догадываюсь, но я бы сказал, что 1d массив быстрее, чем 2d массив. Тем не менее, это не будет заметно быстрее. Вроде как 1 000 000,01 долларов США - это более 1 000 000 долларов США.

Я бы использовал все, что проще для написания кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...