C# 如何加快计算速度
给定两个用整数表示的ARGB颜色,8位/通道(alpha、红色、绿色、蓝色),我需要计算一个表示它们之间某种距离(也是整数)的值 所以距离的公式是:C# 如何加快计算速度,c#,performance,C#,Performance,给定两个用整数表示的ARGB颜色,8位/通道(alpha、红色、绿色、蓝色),我需要计算一个表示它们之间某种距离(也是整数)的值 所以距离的公式是:Delta=|R1-R2 |+| G1-G2 |+| B1-B2 |,其中Rx、Gx和Bx是颜色1和2的通道值。Alpha通道始终被忽略 我需要加速这个计算,因为在一台速度较慢的机器上要做很多次。对于给定两个整数的单个线程,“极客”是如何计算的 到目前为止,我的最好成绩是,但我想这还可以进一步提高: //Used for color conv
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;
}
您可以这样做以减少和操作:
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;
}
不是很多,但有些东西…一个想法是使用与您已有的代码相同的代码,但顺序不同:应用掩码,获取差异,然后移位 另一个可能有用的修改是内联这个函数:也就是说,不需要为每一对颜色调用它,只需在执行此代码的任何循环中直接计算差异。我假设它处于一个紧密的循环中,因为否则它的成本可以忽略不计 最后,由于您可能正在获取图像像素数据,您可以通过执行
不安全的路线节省大量资源:这样制作位图,然后抓取字节*并从中读取图像数据。详细答案:
多少是“很多”
我想我有一台速度很快的机器,但我写了这个小脚本:
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();
}
根据这一变化,输出为:5546。因此,通过返回一个常量,我们在1亿次迭代中获得了1秒的性能增益。;)
简短回答:此功能不是您的瓶颈。:) 我试图让运行时为我计算
首先,我用显式字段偏移量定义struct
[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();
}
public void FactMethodName2()
{
var s=Stopwatch.StartNew();
var color1=new Color();//这是一个结构,因此我可以在循环外定义它们并获得一些性能
var color2=新颜色();
对于(int i=0;i<100000000;i++)
{
颜色1.Raw=i;
颜色2.原始值=100000000-i;
int compute=ComputeColorDeltaOptimized(color1,color2);
}
Console.WriteLine(s.elapsedmillyses);//5393对7472的原始版本
Console.ReadLine();
}
前两个问题:您确定这是您的瓶颈吗?你是通过分析确定的吗?我不认为这有什么错。这似乎不太可能是瓶颈。您是否分析过以确认这是瓶颈?您是否进行了性能测试以确定当前性能是否不足?在开始之前,您是否能够轻松地将这两个映像转换为字节数组而不是整数数组?这将使计算更简单,因为您只需在不进行任何移位的情况下找到字节值之间的差异。哦,如果有一种简单的方法从.Net访问SIMD就好了:)我不相信这是正确的:通道将相互干扰。考虑“0x0FF00 -0x000”FF:您的公式为绿色通道差异提供“0xFE”。你必须先将遮罩应用到每种颜色上。不,你的公式先取差值,然后移动。区别在于0x00FE01
,移位0x00FE
,掩蔽0xFE
。谢谢:)记录在案,如果我发布自己的答案,我不会投反对票,所以不是我:)我想随机投票会占用大部分时间,如果您只是将i
传递到ComputeColorDelta
中,然后进行比较,那么运行时会怎么样?@aquinas会更改您的代码,首先将所有随机数生成到一个列表中,而使用新的StopWatch()默认构造函数,分别调用.Start()和.Stop()?我认为你的第一个衡量标准是衡量r.Next()的成本也是两倍。我只是想说明一点,我并不是说这是有史以来最好的基准:)这是一个很好的观点。但我分别得到1237和40。如果可能的话,绝对值得优化该代码。将黑色改为蓝色,但无论如何+1显示FieldOffset,我没有意识到这一点
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();
}