我有一个后台线程,它从设备读取消息并格式化它们并将它们传递给Producer / Consumer集合的'Consumer'节点,然后将所有消息打印到字符串。我遇到的问题是日志记录滞后于进程结束,所以我试图找到一种更快的方式来打印到屏幕上。这是我的消费者方法:
private void DisplayMessages(BlockingCollection<string[]> messages)
{
try
{
foreach (var item in messages.GetConsumingEnumerable(_cancellationTokenSource.Token))
{
this.Invoke((MethodInvoker)delegate
{
outputTextBox.AppendText(String.Join(Environment.NewLine, item) + Environment.NewLine);
});
}
}
catch (OperationCanceledException)
{
//TODO:
}
}
我已经对我的生产者方法进行了一些基准测试,甚至登录到控制台,看起来写入这个TextBox的速度有点慢。在每个过程中,我正在记录约61,000行,大约60个字符。
我研究过使用.AppendText()比使用textBox.Text += newText
更好,因为这会重置整个TextBox的文本。我正在寻找一种解决方案,可能包括更快的方式打印到TB(或更适合快速记录的UI元素?),或者如果使用String.Join(Environment.NewLine, item)
效率低下并且可以以任何方式加速。
答案 0 :(得分:3)
具有O(n ^ 2)性能的代码预计会很慢。
如果您不能使用String.Join
构建整个输出,那么请考虑使用面向列表的控件甚至网格。如果您的行数非常多,则大多数列表控件和网格都具有“虚拟”模式,其中文本实际上是按需请求的。
答案 1 :(得分:1)
String.Join效率不高。它被调用的方式会导致它被调用N次(对于集合中的每个消息arrau一次)而不是一次。您可以通过使用SelectMany展平集合来避免这种情况。 SelectMany将IEnumerable作为输入并返回其中的每个项目:
var allLines=messages.SelectMany(msg=>msg);
var bigText=String.Join(allLines,Environment.NewLine);
使用这么大的文本框会非常困难。您应该考虑使用虚拟化网格或列表框,添加过滤器和搜索功能,以便用户更轻松地找到他们想要的消息。
另一种选择可能是简单地将行分配给TextBox.Lines属性而不创建字符串:
var allLines=messages.SelectMany(msg=>msg);
outputTextBox.Lines=allLines.ToArray();