Как в С# ускорить копирование из массива в массив?

Есть класс например:

public class PixArray
{
    public byte[] img = new byte[1920 * 1080 * 3];

    public void Merge(PixArray img2)
    {
        //тут просто копирование массива в массив через for
        //это не статичный метод и он использует this.img в процессе
        //я могу сделать статичный метод который возвращает значение если нужно (это не сложно)
    }
}

Метод Merge занимает около 100 мс, а мне нужно максимум 13. Как я могу ускорить вычисления? Перенести на GPU?


Ответы (3 шт):

Автор решения: rotabor

А не нужно "for" использовать. Пользуйтесь "Array.Copy" или "Array.CopyTo":

public class PixArray
{
    public byte[] img = new byte[1920 * 1080 * 3];

    public void Merge(byte[] img2)
    {
        img.CopyTo(img2, 0);
    }
}
→ Ссылка
Автор решения: aepot

Как было сказано в комментариях, GPU вам никак не поможет в копировании памяти, у видеокарты другое назначение.

Самый быстрый вариант копирования данных из одного одномерного массива в другой:

Buffer.BlockCopy(img, 0, img2.img, 0, img.Length);

Быстрее ничего не найдёте. Можно ещё через неуправляемый доступ к памяти, но не факт, что это будет быстрее.

Есть альтернатива, её сравнительная производительность зависит от процессора и версии .NET

Array.Copy(img, img2.img, img.Length);

Можете протестировать оба варианта и выбрать тот, что понравится больше.


Кстати, посмотрел код этих методов. В последней версии .NET (.NET 9) оба метода под капотом делают совершенно одно и то же, но Buffer.BlockCopy немного посвежее написан, так что я бы отдал предпочтение ему, во всяком случае для одномерного массива байт.

→ Ссылка
Автор решения: Vasily Zhavoronkov
public void Merge(PixArray imgToMerge, Vector2int? imgPos = null)
        {
            imgPos = imgPos ?? new();

            int imgToMergeLayer = imgToMerge.Width * 3;
            int thisImgLayer = this.Width * 3;
            int elsToSkipX = 3 * imgPos.x;
            int numOfEls = imgToMergeLayer;
            if (elsToSkipX + numOfEls > thisImgLayer) numOfEls = thisImgLayer - elsToSkipX;
            if (numOfEls < 1) return;


            if (elsToSkipX >= 0) for (int i = imgPos.y >= 0 ? imgPos.y : 0; i - imgPos.y < imgToMerge.Height && i < this.Height; i++)
                        {
                            Array.Copy(imgToMerge.img, (i - imgPos.y) * imgToMergeLayer, this.img, i * thisImgLayer + elsToSkipX, numOfEls);
                        }
                    
            else if (elsToSkipX * -1 < imgToMergeLayer) for (int i = imgPos.y >= 0 ? imgPos.y : 0; i - imgPos.y < imgToMerge.Height && i < this.Height; i++)
                        {
                            Array.Copy(imgToMerge.img, (i - imgPos.y) * imgToMergeLayer - elsToSkipX, this.img, i * thisImgLayer, numOfEls + elsToSkipX);
                        }
        }

Спасибо! (Сложность была в том что изображения могут не соответствуют по размерам и нужно учитывать координаты) этот метод выполняется меньше чем за 1мс (при 1920x1080 исходное и 1801x896 накладываемое)

→ Ссылка