我有一个程序,根据结果的不同,以某种方式对返回的结果进行颜色编码。由于对结果进行颜色编码所花费的时间长度(目前正在使用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++;
}
});
答案 0 :(得分:4)
代码中的大部分时间很可能花在实际选择richtext框中文本并设置颜色的部分中。
此代码不可能并行执行,因为它必须编组到UI线程 - 您通过tempRTB.Invoke
执行此操作。
此外,您明确确保突出显示不是并行执行,而是使用lock
语句按顺序执行。这是不必要的,因为所有代码都在单个UI线程上运行。
您可以尝试通过在为RTB中的文本选择和着色时暂停UI的布局来提高性能:
tempRTB.SuspendLayout();
// your loop
tempRTB.ResumeLayout();
答案 1 :(得分:3)
您的程序实际上没有任何方面实际上能够并行运行。
匹配的生成需要按顺序进行。在找到第一个匹配之前,它找不到第二个匹配项。 Parallel.ForEach
充其量只允许您并行处理序列的结果,但它们仍然是生成的顺序。这是你大部分耗时工作的地方,而且那里没有收获。
最重要的是,您并非真正并行处理结果。在循环体中运行的大多数代码都在UI线程的调用内,这意味着它全部由单个线程运行。
简而言之,程序中只有一小部分实际并行运行,并且通常使用并行化会增加一些开销;听起来你只是勉强得到的不仅仅是开销。没有太多你做错误的,操作本来就不适合并行化,除非有一种有效的方法将初始字符串分解为几个较小的chucks,正则表达式可以单独解析(并行)。