C#慢搜索

时间:2012-03-18 12:37:50

标签: c# performance sorting

我创建了一个简单的数组,其中包含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分钟?

4 个答案:

答案 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);
        }

    }

并尝试启用optimization instruction for compiler

答案 1 :(得分:1)

有一个原则,我认为这里不适用,这会增加表现。从我看到的,你的数组没有排序,搜索是线性的。因此,对于第一个数组中的每一行,都会搜索第二个数组的所有行。

以下是一些要测试的内容: - 对第二个阵列进行排序(在其上执行搜索) - Array.find()而不是自己循环

答案 2 :(得分:1)

您可以尝试使用颜色计数对列表(而不是两个数组),并将其按颜色索引排序。然后使用二进制搜索来查找重复的颜色。我怀疑这比使用字典更快,但这也许值得尝试(?)。

排序和二分查找:http://msdn.microsoft.com/en-us/library/b0zbh7b6.aspx#Y700

字典:http://msdn.microsoft.com/en-us/library/xfhwa508.aspx

答案 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(); 

(没有编译器编写,所以你可能需要调整它)

看看情况如何。