C# 这个流行的答案不正确吗?

C# 这个流行的答案不正确吗?,c#,performance,optimization,C#,Performance,Optimization,我所指的帖子不仅是在将大小增加到100000000时,第一个对我来说运行得更快(563毫秒,而不是630毫秒),而且在过去,在for循环中使用属性导致了相当大的速度减慢 在编写波形查看器时,每帧平均需要23毫秒处理一次。贯穿整张图片像素的for循环是导致速度减慢的原因。我不是在for循环之前存储图片的宽度和高度,而是在每次迭代中访问它。更改后,处理单个帧的时间从23毫秒变为3毫秒 此外,我还制作了以下示例类: class LOL { private int x; public

我所指的帖子不仅是在将大小增加到100000000时,第一个对我来说运行得更快(563毫秒,而不是630毫秒),而且在过去,在for循环中使用属性导致了相当大的速度减慢

在编写波形查看器时,每帧平均需要23毫秒处理一次。贯穿整张图片像素的for循环是导致速度减慢的原因。我不是在for循环之前存储图片的宽度和高度,而是在每次迭代中访问它。更改后,处理单个帧的时间从23毫秒变为3毫秒

此外,我还制作了以下示例类:

class LOL
{
    private int x;

    public LOL(int x)
    {
        this.x = x;
    }

    public int X
    {
        get
        {
            return x;
        }
    }
}
然后我做了一个for循环,循环次数为500000000次。一个测试在循环开始之前将X存储在整数变量中,另一个测试在每次迭代期间访问X属性。前者大约需要1500毫秒,后者大约需要8000毫秒


三次测试,每一次测试的结果都表明,提前存储限制是提高性能的最佳解决方案。我错过什么了吗?目前,在我的程序中,由于需要处理大型图片,因此需要进行优化。在所有性能关键区域,我总是在手头存储循环的边界,以提高性能,这些测试似乎证实了这一点。

不,我觉得这是正确的;如果我运行这个:

int[] values = new int[100000000];

var watch = Stopwatch.StartNew();
int length = values.Length;
for (int i = 0; i < length; i++)
    values[i] = i;
watch.Stop();
var hoisted = watch.ElapsedMilliseconds;

watch = Stopwatch.StartNew();
for (int i = 0; i < values.Length; i++)
    values[i] = i;
watch.Stop();
var direct = watch.ElapsedMilliseconds;
int[]值=新的int[100000000];
var watch=Stopwatch.StartNew();
int length=值。长度;
for(int i=0;i

并通过优化构建,从控制台运行;我得到了
direct
as 71和
highed
as 163,这与我所期望的JIT消除对向量的越界检查(但仅当直接访问时)相关联。

release模式下编译,缓存的长度更快。在调试时,情况正好相反

试验方法

public static class Performance
{
    public static void Test(string name, decimal times, bool precompile, Action fn)
    {
        if (precompile)
        {
            fn();
        }

        GC.Collect();
        Thread.Sleep(2000);

        var sw = new Stopwatch();

        sw.Start();

        for (decimal i = 0; i < times; ++i)
        {
            fn();
        }

        sw.Stop();

        Console.WriteLine("[{0,15}: {1,-15}]", name, new DateTime(sw.Elapsed.Ticks).ToString("HH:mm:ss.fff"));
        Debug.WriteLine("[{0,15}: {1,-15}]", name, new DateTime(sw.Elapsed.Ticks).ToString("HH:mm:ss.fff"));
    }
}
发布结果

[   Direct: 00:00:06.474   ]
[   Cache:  00:00:06.907   ]
[   Direct: 00:00:05.382   ]
[   Cache:  00:00:04.714   ]

“在过去,在for循环中使用属性会导致相当大的速度减慢”-这完全取决于循环的确切性质。当对数组执行此操作时,JIT接受一个提示并对循环中的数组访问执行一些边界检查。这和你的测试不一样,听起来好像它实际上没有在循环中做任何事情……我假设你运行的是发行版,没有附加调试程序?你是在比较苹果和桔子。图像的宽度和高度属性与数组大小无关。是的,它们很昂贵,通过非托管GDI+代码需要往返。在循环它们之前,你总是想把它们检索到一个局部变量中。它们的速度对我来说都差不多,但第二个稍微快一点。我认为第一个对我来说更快的原因是因为我在存储了长度后启动了秒表。我想这没什么意义。不管怎样,谢谢你的回复。我现在明白了=)你知道,如果我颠倒测试发生的顺序(先直接测试,然后再提升),在
Release
中编译并启用优化,我会得到相反的结果。提升约84ms,直接提升约150ms。当我把你的代码粘贴进去时,我得到了相反的结果(即direct更快)。@David-hmm。。。。我认为这指向了JIT进行/不进行优化的不同场景。我不能修改你的数字,但我可以让它们保持一致——意思是:它没有应用optimise@David我也得到了相反的结果。@BrunoLM-我想知道这些方法的初始化(不是JIT的吗?)是否会增加一些开销,并可能会扭曲结果。不过,我只是在猜测。我的数字大不相同;在这个场景中,我基本上得到了相同的时间安排——与您引用的“发布结果”完全不同。在调试中,缓存版本的速度明显较慢。
[   Direct: 00:00:05.382   ]
[   Cache:  00:00:04.714   ]