Parallel.ForEach和Regex没有性能提升?

时间:2013-05-14 14:29:37

标签: c# regex multithreading .net-4.0 parallel-processing

我有一个程序,根据结果的不同,以某种方式对返回的结果进行颜色编码。由于对结果进行颜色编码所花费的时间长度(目前正在使用Regex和RichTextBox.Select + .SelectionColor完成),因此我将结果处理为400的颜色编码。在这个数字左右,它需要大约20秒,这是我认为合理的最大时间。

为了尝试提高性能,我重新编写了Regex部分,使用Parallel.ForEach循环遍历MatchCollection,但时间大致相同(18-19秒vs 20)!是不是一个非常适合并行编程的工作?我应该尝试不同的东西吗?欢迎任何建议。谢谢!

PS:我觉得有点奇怪的是,无论有没有Parallel.ForEach,我的CPU利用率都不会达到14%左右。

代码

MatchCollection startMatches = Regex.Matches(tempRTB.Text, startPattern);

object locker = new object();
System.Threading.Tasks.Parallel.ForEach(startMatches.Cast<Match>(), m =>
{
    int i = 0;
    foreach (Group g in m.Groups)
    {
        if (i > 0 && i < 5 && g.Length > 0)
        {
            tempRTB.Invoke(new Func<bool>(
                delegate
                {
                    lock (locker)
                    {
                        tempRTB.Select(g.Index, g.Length);
                        if ((i & 1) == 0) // Even number
                            tempRTB.SelectionColor = Namespace.Properties.Settings.Default.ValueColor;
                        else              // Odd number
                            tempRTB.SelectionColor = Namespace.Properties.Settings.Default.AttributeColor;
                        return true;
                    }
                }));
        }
        else if (i == 5 && g.Length > 0)
        {
            var result = tempRTB.Invoke(new Func<string>(
                delegate
                {
                    lock (locker)
                    {
                        return tempRTB.Text.Substring(g.Index, g.Length);
                    }
                }));

            MatchCollection subMatches = Regex.Matches((string)result, pattern);

            foreach (Match subMatch in subMatches)
            {
                int j = 0;
                foreach (Group subGroup in subMatch.Groups)
                {
                    if (j > 0 && subGroup.Length > 0)
                    {
                        tempRTB.Invoke(new Func<bool>(
                            delegate
                            {
                                lock (locker)
                                {
                                    tempRTB.Select(g.Index + subGroup.Index, subGroup.Length);
                                    if ((j & 1) == 0) // Even number
                                        tempRTB.SelectionColor = Namespace.Properties.Settings.Default.ValueColor;
                                    else              // Odd number
                                        tempRTB.SelectionColor = Namespace.Properties.Settings.Default.AttributeColor;
                                    return true;
                                }
                            }));
                    }
                    j++;
                }
            }
        }
        i++;
    }
});

2 个答案:

答案 0 :(得分:4)

代码中的大部分时间很可能花在实际选择richtext框中文本并设置颜色的部分中。

此代码不可能并行执行,因为它必须编组到UI线程 - 您通过tempRTB.Invoke执行此操作。

此外,您明确确保突出显示不是并行执行,而是使用lock语句按顺序执行。这是不必要的,因为所有代码都在单个UI线程上运行。


您可以尝试通过在为RTB中的文本选择和着色时暂停UI的布局来提高性能:

tempRTB.SuspendLayout();

// your loop

tempRTB.ResumeLayout();

答案 1 :(得分:3)

您的程序实际上没有任何方面实际上能够并行运行。

匹配的生成需要按顺序进行。在找到第一个匹配之前,它找不到第二个匹配项。 Parallel.ForEach充其量只允许您并行处理序列的结果,但它们仍然是生成的顺序。这是你大部分耗时工作的地方,而且那里没有收获。

最重要的是,您并非真正并行处理结果。在循环体中运行的大多数代码都在UI线程的调用内,这意味着它全部由单个线程运行。

简而言之,程序中只有一小部分实际并行运行,并且通常使用并行化会增加一些开销;听起来你只是勉强得到的不仅仅是开销。没有太多你做错误的,操作本来就不适合并行化,除非有一种有效的方法将初始字符串分解为几个较小的chucks,正则表达式可以单独解析(并行)。