如何加快计算速度

本文关键字:速度 计算 何加快 | 更新日期: 2023-09-27 18:07:30

给定以整数表示的两种ARGB颜色,8位/通道(alpha,红色,绿色,蓝色),我需要计算一个表示它们之间某种距离(也是整数)的值。

则距离的公式为:Delta=|R1-R2|+|G1-G2|+|B1-B2|,其中Rx, Gx和Bx分别为颜色1和2通道的值。Alpha通道总是被忽略。

我需要加速这个计算,因为它在一台慢速机器上做了很多次。在给定两个整数的情况下,在单个线程上计算这个的"极客"方法是什么?

到目前为止我最好的是,但我想这可以进一步改进:

    //Used for color conversion from/to int
    private const int ChannelMask = 0xFF;
    private const int GreenShift = 8;
    private const int RedShift = 16;
    public int ComputeColorDelta(int color1, int color2)
    {
        int rDelta = Math.Abs(((color1 >> RedShift) & ChannelMask) - ((color2 >> RedShift) & ChannelMask));
        int gDelta = Math.Abs(((color1 >> GreenShift) & ChannelMask) - ((color2 >> GreenShift) & ChannelMask));
        int bDelta = Math.Abs((color1 & ChannelMask) - (color2 & ChannelMask));
        return rDelta + gDelta + bDelta;
    }

如何加快计算速度

长答:

"a lot"是多少

我猜我的机器很快,但是我写了这个小脚本:

 public static void Main() {
            var s = Stopwatch.StartNew();
            Random r = new Random();
            for (int i = 0; i < 100000000; i++) {
                int compute = ComputeColorDelta(r.Next(255), r.Next(255));
            }
            Console.WriteLine(s.ElapsedMilliseconds);
            Console.ReadLine();
        }

,输出为:6878

所以7秒1亿次看起来很不错。

我们绝对可以加快速度。我把你的函数改成这样:

public static int ComputeColorDelta(int color1, int color2) {
  return 1;
}

修改后,输出为:5546。因此,我们通过返回一个常量,在1亿次迭代中获得了1秒的性能增益。;)

简短的回答:这个函数不是你的瓶颈。:)

我想让运行时为我做计算。

首先,我用显式字段偏移定义结构体

[StructLayout(LayoutKind.Explicit)]
public struct Color
{
    [FieldOffset(0)] public int Raw;
    [FieldOffset(0)] public byte Blue;
    [FieldOffset(8)] public byte Green;
    [FieldOffset(16)] public byte Red;
    [FieldOffset(24)] public byte Alpha;
}

计算函数为:

public int ComputeColorDeltaOptimized(Color color1, Color color2)
{
    int rDelta = Math.Abs(color1.Red - color2.Red);
    int gDelta = Math.Abs(color1.Green - color2.Green);
    int bDelta = Math.Abs(color1.Blue - color2.Blue);
    return rDelta + gDelta + bDelta;
}

的用法
public void FactMethodName2()
{
    var s = Stopwatch.StartNew();
    var color1 = new Color(); // This is a structs, so I can define they out of loop and gain some performance
    var color2 = new Color(); 
    for (int i = 0; i < 100000000; i++)
    {
        color1.Raw = i;
        color2.Raw = 100000000 - i;
        int compute = ComputeColorDeltaOptimized(color1, color2);
    }
    Console.WriteLine(s.ElapsedMilliseconds); //5393 vs 7472 of original 
    Console.ReadLine();
}

一个想法是使用您已经拥有的相同代码,但以不同的顺序:应用掩码,取差值,然后移位。

另一个可能有帮助的修改是内联这个函数:也就是说,不是为每一对颜色调用它,而是在执行这段代码的任何循环中直接计算差异。我假设它是在一个紧循环中,否则它的代价可以忽略不计。

最后,因为你可能得到图像像素数据,你会节省很多通过unsafe路线:使你的位图像这个EditableBitmap,然后抓取字节*和读取图像数据。

这样做是为了减少AND操作:

public int ComputeColorDelta(int color1, int color2)
{
    int rDelta = Math.Abs((((color1  >> RedShift) - (color2  >> RedShift))) & ChannelMask)));
    // same for other color channels
    return rDelta + gDelta + bDelta;
}