Целочисленный массив или массив структур - который лучше?

В моем приложении я храню Bitmap данные в двумерном целочисленном массиве (int[,]). Получить доступ к R, G и B оценивает, я использую что-то вроде этого:

// read:
int i = _data[x, y];
byte B = (byte)(i >> 0);
byte G = (byte)(i >> 8);
byte R = (byte)(i >> 16);
// write:
_data[x, y] = BitConverter.ToInt32(new byte[] { B, G, R, 0 }, 0);

Я использую целочисленные массивы вместо фактического System.Drawing.Bitmap потому что мое выполнение приложения на устройствах Windows Mobile, где память, доступная для создания битовых массивов, сильно ограничена.

Я задаюсь вопросом, тем не менее, если имело бы больше смысла объявлять структуру как это:

public struct RGB
{
    public byte R;
    public byte G;
    public byte B;
}

... и затем используйте массив RGB вместо массива int. Таким образом, я мог легко считать и записать отдельный R, G и значения B, не имея необходимость делать смещение бита и BitConverter-луг. Я неопределенно помню что-то со дней былого о byte переменные, выравниваемые блоком в 32-разрядных системах, так, чтобы a byte на самом деле поднимает 4 байта памяти вместо всего 1 (но возможно это было просто вещью Visual Basic).

Был бы с помощью массива структур (как RGB пример' выше), быть быстрее, чем использование массива ints, и это использовало бы 3/4 память или 3 раза память ints?

5
задан MusiGenesis 14 March 2010 в 07:16
поделиться

4 ответа

Если вы используете примерно скорость , то технически я бы ожидал int [] версия будет быстрее, так как есть специальная инструкция IL для получения int из массива (см. OpCodes.Ldelem_I4 ). Чтобы создать настраиваемую структуру, она должна получить адрес ( OpCodes.Ldelema ), а затем скопировать структуру ( OpCodes.Ldobj ) - обработать метаданные типа для обоих этих шагов.

Короче говоря, подход int должен иметь лучшую оптимизацию.Но это микрооптимизация - в общем предпочитайте версию, которая делает ваш код более читабельным. Что вы могли бы рассмотреть, так это написать структуру с пользовательским статическим оператором неявного преобразования из int в вашу структуру - тогда вы можете иметь int [] и по-прежнему делать :

MyColor col = intArr[12];

(он, конечно, выполнит статический вызов посередине)

Вы также можете рассмотреть возможность использования объединения , чтобы вам не нужно было много сдвигать:

ВАЖНО Я не проверял правильность порядка байтов в здравом уме; просто измените смещения R / G / B, чтобы изменить его.

class Program
{
    static void Main()
    {
        int[] i = { -1 };
        RGB rgb = i[0];
    }
}
[StructLayout( LayoutKind.Explicit)]
public struct RGB
{
    public RGB(int value) {
        this.R = this.G = this.B = 0; this.Value = value;
    }
    [FieldOffset(0)]
    public int Value;
    [FieldOffset(2)]
    public byte R;
    [FieldOffset(1)]
    public byte G;
    [FieldOffset(0)]
    public byte B;

    public static implicit operator RGB(int value) {
        return new RGB(value);
    }
    public static implicit operator int(RGB value) {
        return value.Value;
    }
}
2
ответ дан 14 December 2019 в 08:48
поделиться

Отдельный байт, вероятно, будет выровнен по блокам, но несколько байтов в структуре могут быть упакованы. Согласно Marshal.SizeOf, ваша структура RGB действительно занимает всего три байта памяти. (Технически это размер при маршалинге в неуправляемую память, и CLR может выбрать другой вариант размещения; но на практике я думаю, что это будет правильно.)

Однако CLR все еще может вставлять отступы между RGB и другими структур, и это поведение может зависеть от процессора, версии CLR и т. д. В системе x86 выделение массива из 300 миллионов RGB привело к тому, что диспетчер задач сообщил о выделении примерно 900 МБ, тогда как выделение массива из 300 миллионов int привело к выделению 1200 МБ. . Таким образом, похоже, что 2.0 CLR на x86 дает вам 25% экономии. (Должен признать, это меня удивило; как и Traveling Tech Guy, я ожидал, что 3-байтовые структуры будут выровнены по 4-байтовой границе. Так что я могу чего-то упустить.) Но CF может быть другим: вы действительно узнайте, только протестировав его на вашей целевой платформе.

2
ответ дан 14 December 2019 в 08:48
поделиться

Почему бы просто не использовать структуру Color в System.Drawing ? С ним проще обращаться и ссылаться. Конечно, он имеет 4 байта (другое значение представляет Alpha), но то же самое относится и к вашей первой реализации, и, если я правильно помню, любые 3 байта в любом случае будут выровнены с 4-байтовым блоком. Взгляните на образец здесь .

2
ответ дан 14 December 2019 в 08:48
поделиться

Я думаю, это зависит от того, чего вы хотите добиться. Конечно, он более удобен для чтения, чем struct, и вы можете смело использовать его с

unsafe { }

что действительно ускорит доступ к Bitmap. (Если вы знаете, что делать - без проверки граничных условий и тому подобного). И, конечно, если вы хотите сделать операторы для умножения растровых изображений, маскирования, градации серого, фильтрации и т.д., то INT - ваш друг в плане скорости, но, к сожалению, не в плане читабельности. Матричный фильтр только умножает указанные инты (так можно написать), а не RGB значения независимо, но со структурой Marks это не должно быть проблемой в любом случае. Надеюсь, это поможет

1
ответ дан 14 December 2019 в 08:48
поделиться
Другие вопросы по тегам:

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