1

我有一个BackgroundWorker发布消息的线程,BeginInvoke在 GUI 的文本框中使用。write_debug_text在文本框中显示文本的方法使用AppendText并将文本写入Console.

外观是BackgroundWorker写得太快write_debug_text,跟不上。我设置了一个断点,write_debug_text并且必须等待很长时间才能被击中。许多对“BeginInvoke”的调用发生在断点被命中之前。

我正在寻找 UI 上消息的实时显示,就像System.Console在 VS C# Express IDE 中一样。

通过搜索 SO,我了解到这AppendText是使用更快的方法,并且可能必须重新分配字符串。

一些回复建议使用StringBuilder然后定期将该文本写入文本框。但这需要添加更多的事件和计时器;我宁愿不这样做(我的简单应用程序变得越来越复杂)。

我怎样才能实时写入文本框(并让它显示)?

我目前的想法是创建一个继承自 Textbox 的小部件,该小部件使用文本队列和计时器。

编辑 1:示例代码

这是我的代码片段:

    private m_textbox;
    //...
    m_textbox.BeginInvoke(new write_debug_text_callback(this.write_debug_text),
                                      new object[] { debug_text });
    return;

private void write_debug_text(string text)
{
    string time_stamp_text = "";
    time_stamp_text = DateTime.Now.ToString() + "   ";
    time_stamp_text += text;
    m_textbox.AppendText(time_stamp_text);
    m_textbox.Update();
    System.Console.Write(time_stamp_text);
    return;
}

我已尝试更改BeginInvokeInvoke,但我的应用程序已挂起。当我使用调试器暂停/中断时,执行指针位于对Invoke.

顺便说一句,我在 Java、C++ 和 C 方面有多年的经验。我在 C# 的第 5 个月。

4

6 回答 6

1

如果显示的消息很多,那么问题很可能是内存分配问题。

假设每条消息的长度为 30 个字符。这将是(大约)60 个字节。让我们进一步假设您每秒添加 10 条消息。然后,在第一秒生成的字符串将为:60 + 120 + 60 + 180 + 60 + 240 + 60 + 300 + ... + 60 + 600 = 3840 字节。在第二秒,总数上升到 13,740 字节。第三秒:29,640。第四名:51,540。... 第 10 位:308,940 字节。

18 秒后,达到 1 MB,显示的字符串为 11 kb。

在一分钟标记处,我们分配了 10 Mb 的字符串。两分钟后,43 Mb 专用于这些消息,并且每个字符串的大小增加到 71 kb。三分钟后,消息的大小超过 100 kb,其中有近 100 Mb 专门用于它们。

这就是为什么 StringBuilder 对于构建长字符串如此重要的原因!

但是由于您的计划是显示每个中间步骤,因此 StringBuilder 不会在这里为您提供帮助。此 GUI 要求您生成字符串的公制船负载。

这个问题的一种可能的解决方案是在将数据插入到后面时切断字符串的前面。您仍然会为字符串分配大量内存,但各个字符串本身的大小是有限的,因此,运行时在内存中为它们找到位置会容易得多,并且分配速率将一路走下去。

这应该会减少您的垃圾收集压力:

private const int maxDisplayTextLength = 5000;

private void write_debug_text(string text)
{
    string time_stamp_text = "";
    time_stamp_text = DateTime.Now.ToString() + "   " + text;
    string previous = m_textbox.Text;
    if (previous.Length + time_stamp_text.Length > maxDisplayTextLength)
         m_textbox.Text = previous.Substring(0, maxDisplayTextLength - time_stamp_text.Length) + time_stamp_text;
    else
         m_textbox.Text = previous + time_stamp_text;
    m_textbox.Update();
    System.Console.Write(time_stamp_text);
    return;
} 
于 2011-03-30T19:55:33.840 回答
1

也许尝试http://sourceforge.net/projects/fastlogconsole - 具有出色的性能

于 2012-09-13T12:21:39.693 回答
0

如果你想在文本框中实时写入,为什么不使用同步Invoke而不是BeginInvoke稍后调用函数的队列呢?

于 2011-03-30T18:52:16.860 回答
0

不要使用BeginInvoke. 改为使用Invoke。请参阅添加数千行时应用程序变得无响应。这不是完全相同的问题(他使用的是 DataGridView 而不是文本框),但它是同一类事情。您BackgroundWorker正在启动一大堆异步任务。你最好一次做一个。

于 2011-03-30T18:52:56.643 回答
0

您可以尝试改用RichTextBox控件,并阻止它刷新其 UI,除非每隔一段时间。有点像这个StringBuilder建议,但更简单一些。有关如何执行此操作的示例,请参见此SO 问题,

于 2011-03-30T18:54:45.083 回答
0

我使用了@Jeffre L. Whitledge 的建议并减少了字符串分配的数量。由于这是一个具有固定数量字符串的封闭应用程序,因此我缓存了这些字符串。这产生了我的程序执行速度明显更快的副作用。

我的问题之一仍然是 Windows 响应消息的速度很慢。这可以在更新进度条时看到。从发送消息(例如附加文本)到执行消息之间存在一定的延迟。

于 2011-05-14T21:53:52.257 回答