C# Parallel.ForEach和Regex没有性能提升?
我有一个程序,它根据返回的结果以某种方式对返回的结果进行颜色编码。由于对结果进行颜色编码所需的时间很长(目前正在使用Regex和RichTextBox.Select+.SelectionColor进行),我在400个结果时取消了颜色编码。在这个数字上大约需要20秒,这大约是我认为合理的最大时间。 为了提高性能,我重新编写了Regex部分,使用C# Parallel.ForEach和Regex没有性能提升?,c#,regex,multithreading,.net-4.0,parallel-processing,C#,Regex,Multithreading,.net 4.0,Parallel Processing,我有一个程序,它根据返回的结果以某种方式对返回的结果进行颜色编码。由于对结果进行颜色编码所需的时间很长(目前正在使用Regex和RichTextBox.Select+.SelectionColor进行),我在400个结果时取消了颜色编码。在这个数字上大约需要20秒,这大约是我认为合理的最大时间。 为了提高性能,我重新编写了Regex部分,使用Parallel.ForEach循环迭代匹配集合,但时间大致相同(18-19秒vs 20秒)!难道这不是一项适合并行编程的工作吗?我应该试试别的吗?欢迎任何
Parallel.ForEach
循环迭代匹配集合
,但时间大致相同(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++;
}
});
MatchCollection startMatches=Regex.Matches(tempRTB.Text,startPattern);
对象锁定器=新对象();
System.Threading.Tasks.Parallel.ForEach(startMatches.Cast(),m=>
{
int i=0;
foreach(m组中的g组)
{
如果(i>0&&i<5&&g.长度>0)
{
tempRTB.Invoke(新函数(
代表
{
锁(储物柜)
{
tempRTB.Select(g.Index,g.Length);
if((i&1)==0)//偶数
tempRTB.SelectionColor=Namespace.Properties.Settings.Default.ValueColor;
else//奇数
tempRTB.SelectionColor=Namespace.Properties.Settings.Default.AttributeColor;
返回true;
}
}));
}
如果(i==5&&g.长度>0)为else
{
var result=tempRTB.Invoke(新函数(
代表
{
锁(储物柜)
{
返回tempRTB.Text.Substring(g.Index,g.Length);
}
}));
MatchCollection subMatches=Regex.Matches((字符串)结果,模式);
foreach(在子匹配中匹配子匹配)
{
int j=0;
foreach(子匹配组中的组子组)
{
如果(j>0&&subGroup.Length>0)
{
tempRTB.Invoke(新函数(
代表
{
锁(储物柜)
{
tempRTB.Select(g.Index+subGroup.Index,subGroup.Length);
if((j&1)==0)//偶数
tempRTB.SelectionColor=Namespace.Properties.Settings.Default.ValueColor;
else//奇数
tempRTB.SelectionColor=Namespace.Properties.Settings.Default.AttributeColor;
返回true;
}
}));
}
j++;
}
}
}
i++;
}
});
代码中的大部分时间很可能花在实际选择richtext框中的文本并设置颜色的部分
这段代码不可能并行执行,因为它必须被封送到UI线程,这是通过tempRTB.Invoke
完成的
此外,通过使用lock
语句明确确保高亮显示不是并行执行,而是顺序执行。这是不必要的,因为所有这些代码都是在单个UI线程上运行的
您可以尝试通过在RTB中选择文本并为其上色时暂停UI布局来提高性能:
tempRTB.SuspendLayout();
// your loop
tempRTB.ResumeLayout();
实际上,程序的任何方面都不能并行运行 需要按顺序生成匹配项。在找到第一个匹配项之前,它无法找到第二个匹配项
Parallel.ForEach
最多允许您并行处理序列的结果,但它们仍然是按顺序生成的。这就是你大部分耗时的工作似乎都在做的地方,而且没有任何收获
除此之外,您也没有真正并行处理结果。循环体中运行的大部分代码都在对UI线程的调用中,这意味着它都由单个线程运行
简言之,只有一小部分程序实际上是并行运行的,通常使用并行化会增加一些开销;听起来你的开销几乎没有超过这个。实际上你没有做错什么,操作本身就不适合并行化,除非有一种有效的方法将初始字符串分解成几个较小的卡盘,正则表达式可以单独(并行)解析.14%的利用率听起来像是四核上的一个核的利用率达到了100%。您的机器上有多少个核?@LukeHennerley Task manager显示8(它是Intel i7-3770)为什么在
Invoke
语句中有锁块?根据定义,由于您使用的是Invoke
,因此代码只能在一个线程上运行,因此不会出现同步问题。@Hershizer33:这证实了我的怀疑:100%的总体CPU利用率/8个内核=12,5%,如果一个内核的利用率为100%。-->您的UI线程正在完全利用其核心。我明白了,我认为这是有道理的。那么它是什么呢?保持400个结果的硬限制,20秒生存?@Hershizer33:你可以尝试减少disa选择的时间