我在存储有关图像信息的数组上运行图像分析代码。不幸的是,代码非常繁重,平均需要25秒来运行单帧。我看到的主要问题是数组寻址。哪个是最快的2d阵列,并且
中存在任何差异水平然后垂直
for (int y = 0; y < array.Length; ++y)
for (int x = 0; x < array[].Length; ++x)
//Code using array[y][x]
和垂直然后horrizontal?
for (int x = 0; x < array[].Length; ++x)
for (int y = 0; y < array.Length; ++y)
//Code using array[y][x]
此外,我试图避免直接寻址并改为使用指针。
for (int y = 0; y < array.Length; ++y)
int* ptrArray = (int*)array[0];
for (int x = 0; x < array[].Length; ++x, ++ptrArray)
//Code using ptrArray for array[y][x]
或
for (int x = 0; x < array[].Length; ++x)
int* ptrArray = (int*)array[0];
for (int y = 0; y < array.Length; ++y, ptrArray += array[].Length)
//Code using ptrArray for array[y][x]
非常感谢任何帮助。 最大
答案 0 :(得分:2)
一种选择是使用反向循环(从for() loop
开始将array.Length
降低到0)
这会让事情变得更快。
例如,
for (int x = array[].Length-1; x >= 0; --x)
int* ptrArray = (int*)array[0];
for (int y = array.Length-1; y >= 0 ; --y, ptrArray += array[].Length)
//Code using ptrArray for array[y][x]
答案 1 :(得分:2)
最重要的规则是,在你描述之前,这都是理论。我并不认为那些坚持分析就是一切的人(没有一些理论,你不比货物崇拜者把椰子放在他们的耳朵上等待飞机的到来更好),但你的理论总是错误的或不完整的,所以分析是至关重要的。
通常,我们希望内部扫描是水平的(就数组而言,而不是图像,但对于大多数格式来说是相同的)。原因是使用如下数组:
00 01 02 03 04 05 06 07 08 09
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
它将被列为:
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
您希望沿着可以加载到CPU缓存中的连续块进行扫描,然后完全使用,而不是逐块扫描并需要定期更改CPU缓存内容。
如果您尝试并行化算法,这一点就更为重要。你希望每个线程处理它自己的连续内存块,就输入和输出而言,而不仅仅是遭受单线程代码对缓存命中频率差的影响,同时也会导致彼此的缓冲区变脏需要提神。这可能是并行化导致速度提升和并行化实际上减慢速度之间的差异。
另一件事是二维数组byte[,]
而不是数组byte[][]
之间的区别,你在“array [y] [x]”问题中的评论让我想知道也许你正在使用。前者获得arr [1,2]的逻辑是:
对于后者,逻辑是:
内存缓存命中频率也不太好。当需要“锯齿状”结构时,后者有好处,但这不是这种情况。 2D几乎总是比数组数组快。
我认为不太可能提供帮助的事情,但我肯定会在你的情况下尝试:
你可以从1d&lt; =&gt;中获得提升。 2d逻辑。有一个单维数组,其中idx = y * width + x。它不应该有明显的区别,但值得尝试。
优化尝试同时提升对.Length
的调用并省略不必要的边界检查,因此您可能会发现手动提升并切换到指针算术没有任何收获,但在您确实需要带来的情况下时间到了它当然值得描绘。
最后。您是否了解过代码在扫描阵列和无所事事时的速度有多快?可能是代码的另一部分是真正的瓶颈,而你正在修复错误的东西。
答案 2 :(得分:1)
我不知道,但你已经提出了这些例子。因此,您可以在循环中运行代码示例并自行进行配置。
var sw = new Stopwatch();
sw.Start();
ExecuteMyCode();
sw.Stop();
Console.WriteLine("Time: " + sw.Elapsed);
您可以使用多线程构造like Parallel.ForEach
来加快处理速度。如果循环中的代码避免了循环迭代之间的依赖关系,那么这将很有效。
答案 3 :(得分:0)
http://msdn.microsoft.com/en-us/library/28k1s2k6.aspx
有一个代码示例。
答案 4 :(得分:0)
如果可能,请尝试重新分配数组,以使第一个维度小于第二个维度。它会大大加快速度。 另一种解决方案是如上所述在单维数组中重新分配数据。
答案 5 :(得分:0)
始终确保最内层循环访问连续内存。
这通常是图像的一行。请注意,在矩形数组中,您应该将其设为最后一个索引:array[y,x]
。
this paper表明内置的C#矩形数组(带有多个索引)非常慢。我以前读过这个,但这是我得到的唯一参考。我将从一个线性数组开始,并为每一行计算一次偏移量。非托管只会帮助您处理非常琐碎的案件。
如果一个帧需要25秒,那么它就是huuuuge,或者你进行非常复杂的处理。在这种情况下,如果为每个输出像素访问许多输入像素,那么花费精力优化内存访问是很有意思的。