Целочисленный массив или структурный массив - что лучше? - PullRequest
5 голосов
/ 14 марта 2010

В моем приложении я храню данные 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 без необходимости сдвига битов и преобразования битов.Я смутно помню кое-что из давних времен, когда переменные byte были выровнены по блокам в 32-битных системах, так что byte на самом деле занимает 4 байта памяти вместо 1 (но, возможно, это было просто в Visual Basic).

Будет ли использование массива структур (как пример RGB выше) быстрее, чем использование массива целых, и будет ли оно использовать 3/4 памяти или в 3 раза больше памяти целых?

Ответы [ 4 ]

2 голосов
/ 14 марта 2010

Одиночный байт сам по себе, вероятно, будет выровнен по блокам, но несколько байтов в структуре могут быть упакованы. И, согласно 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 марта 2010

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

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

MyColor col = intArr[12];

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

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

ВАЖНО У меня нет здравомыслия, проверенного порядком байтов; просто измените смещения 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 марта 2010

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

1 голос
/ 14 марта 2010

Я думаю, что id зависит от того, чего Ты хочешь достичь. Конечно, для структурирования лучше использовать Readabl, и вы можете безопасно использовать его с

unsafe { }

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

...