我创建了一个简单的数组,其中包含2,000,000个用于保存所有RGB的数据,另一个数组用于保存2,000,000个int用于检测到rgb的次数。然后我循环遍历所有6,000,000字节的图片,如下所示:
uint[] colors = new uint[rawImageBytes.Length / 3];
int[] hits = new int[rawImageBytes.Length / 3];
int colorAmount = 0;
int totalRepeats = 0;
int lastTime = Environment.TickCount;
int lastCount = 0;
uint currentColor = 0;
bool found;
for (int i = 0; i < rawImageBytes.Length - 3; i += 3)
{
if (Environment.TickCount - lastTime > 10000)
{
setStatus(((i - lastCount)/10) + " checks per second");
lastTime = Environment.TickCount;
lastCount = i;
}
currentColor = (uint)((rawImageBytes[i] << 0) | (rawImageBytes[i + 1] << 8) | (rawImageBytes[i + 2] << 16));
//set it to false to see if pattern exists
found = false;
//check all patterns
for (int k = 0; k < colorAmount; k++)
{
//if pattern exists
if (colors[k] == currentColor)
{
//dont add it and increase the hit instead
found = true;
hits[k]++;
}
}
//if pattern does not exist, set it
if (found == false)
{
colors[colorAmount] = currentColor;
hits[colorAmount] = 0;
colorAmount++;
}
}
我的日志显示他们的速度从搜索范围增加显着减慢
每秒5724次检查
每秒5847次检查
每秒5959次检查
每秒6044次检查
每秒6318次检查
每秒7096次检查
每秒8530次检查
每秒10680次检查
每秒16233次检查
每秒11469次检查
如何让我的搜索更有效率,以便不需要20分钟?
答案 0 :(得分:4)
我看到的第一个问题是你的命中数组是非常大的。如果你假设一种颜色可能被击中不止一次,那么你的命中数组必须比你的颜色数组短。
我看到的第二个问题是你在颜色数组中找到颜色后不会停止迭代。您应该在 found = true; 语句后放置 break; 。
为什么你不喜欢Dictionary&lt; UINT,INT&GT;你的点击集合类型?你的颜色应该是一个键,命中数应该是一个值:
uint[] colors = new uint[rawImageBytes.Length / 3];
Dictionary<uint,int> hits = new Dictionary<uint,int>();
int colorAmount = 0;
int totalRepeats = 0;
int lastTime = Environment.TickCount;
int lastCount = 0;
uint currentColor = 0;
for (int i = 0; i < rawImageBytes.Length - 3; i += 3)
{
if (Environment.TickCount - lastTime > 10000)
{
setStatus(((i - lastCount)/10) + " checks per second");
lastTime = Environment.TickCount;
lastCount = i;
}
currentColor = (uint)((rawImageBytes[i] << 0) | (rawImageBytes[i + 1] << 8) | (rawImageBytes[i + 2] << 16));
if (hits.ContainsKey(currentColor))
{
hits[currentColor]++;
}
else
{
hits.Add(currentColor,1);
}
}
答案 1 :(得分:1)
有一个原则,我认为这里不适用,这会增加表现。从我看到的,你的数组没有排序,搜索是线性的。因此,对于第一个数组中的每一行,都会搜索第二个数组的所有行。
以下是一些要测试的内容: - 对第二个阵列进行排序(在其上执行搜索) - Array.find()而不是自己循环
答案 2 :(得分:1)
您可以尝试使用颜色计数对列表(而不是两个数组),并将其按颜色索引排序。然后使用二进制搜索来查找重复的颜色。我怀疑这比使用字典更快,但这也许值得尝试(?)。
排序和二分查找:http://msdn.microsoft.com/en-us/library/b0zbh7b6.aspx#Y700
答案 3 :(得分:0)
这看起来像是并行化的一个很好的用例 不要自己做所有的计数/等事情,让我们让LINQ来处理
首先,让我们将迭代器逻辑放入它自己的方法中,这样你就可以单独调整它:
IEnumerable<uint> GetColors(byte[] rawImageBytes)
{
int lastTime = Environment.TickCount;
for (int i = 0; i < rawImageBytes.Length - 3; i += 3)
{
if (Environment.TickCount - lastTime > 10000)
{
setStatus(((i - lastCount)/10) + " checks per second");
lastTime = Environment.TickCount;
lastCount = i;
}
currentColor = (uint)((rawImageBytes[i] << 0) | (rawImageBytes[i + 1] << 8) | (rawImageBytes[i + 2] << 16));
yield return currentColor;
}
}
现在让我们使用PLINQ重写你的方法:
var results = (from color in GetColors(rawImageBytes).AsParallel()
group by color into g
select new { Color = g.Key, Count = g.Count()}).ToList();
var uniqueColours = results.Count();
var totalHits = results.Select(r=>r.Count()).Sum();
(没有编译器编写,所以你可能需要调整它)
看看情况如何。