Как в С# ускорить копирование из массива в массив?
Есть класс например:
public class PixArray
{
public byte[] img = new byte[1920 * 1080 * 3];
public void Merge(PixArray img2)
{
//тут просто копирование массива в массив через for
//это не статичный метод и он использует this.img в процессе
//я могу сделать статичный метод который возвращает значение если нужно (это не сложно)
}
}
Метод Merge занимает около 100 мс, а мне нужно максимум 13. Как я могу ускорить вычисления? Перенести на GPU?
Ответы (3 шт):
А не нужно "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);
}
}
Как было сказано в комментариях, GPU вам никак не поможет в копировании памяти, у видеокарты другое назначение.
Самый быстрый вариант копирования данных из одного одномерного массива в другой:
Buffer.BlockCopy(img, 0, img2.img, 0, img.Length);
Быстрее ничего не найдёте. Можно ещё через неуправляемый доступ к памяти, но не факт, что это будет быстрее.
Есть альтернатива, её сравнительная производительность зависит от процессора и версии .NET
Array.Copy(img, img2.img, img.Length);
Можете протестировать оба варианта и выбрать тот, что понравится больше.
Кстати, посмотрел код этих методов. В последней версии .NET (.NET 9) оба метода под капотом делают совершенно одно и то же, но Buffer.BlockCopy немного посвежее написан, так что я бы отдал предпочтение ему, во всяком случае для одномерного массива байт.
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 накладываемое)