【问题标题】:Quickest way to Update Multiline Textbox with Large Amount of Text使用大量文本更新多行文本框的最快方法
【发布时间】:2013-10-15 17:30:26
【问题描述】:

我有一个使用 ODBC 查询基于文本的数据库的 .NET 4.5 WinForm 程序。然后,我想在多行文本框中显示每个结果,并且我想以最快的方式完成。
在更新/填充文本框期间,GUI 不必可用。但是,如果我可以更新进度条以让用户知道正在发生某些事情,那就太好了 - 我相信为此需要后台工作人员或新线程/任务,但我从未实现过。

我最初使用这段代码,它很慢,因为它在继续下一行之前每行都提取结果。

OdbcDataReader dbReader = com.ExecuteReader();
while (dbReader.Read())
{
   txtDatabaseResults.AppendText(dbReader[0].ToString());
}

这明显更快。

string resultString = "";
while (dbReader.Read())
{
   resultString += dbReader[0].ToString();
}
txtDatabaseResults.Text = resultString;

但是在文本框出现之前有很长的等待时间,所以我想知道操作是否可以更快。现在我从文件中获取大约 7,000 行,我认为没有必要切换到 AvalonEdit(如果我的思维方式错误,请纠正我,但我想保持简单并使用内置的文本框)。

【问题讨论】:

  • 您可能对 My Example 使用当前相关的 .Net Windows UI 技术感兴趣。
  • 只需备注您对后台工作人员或新线程/任务的评论,后台工作人员非常易于使用。前一周我刚刚了解到他们并坠入爱河。 dotnetperls 有一个很好的简单示例来说明如何使用它:dotnetperls.com/progressbar 除了将 i 传递给 ReportProgress 方法之外,您必须执行一些基本的数学运算来确定您的任务的百分比,例如当前行划分按结果集中的总行数。
  • @HighCore 很好的链接和答案,但可能对我当前的应用程序来说太强大了。
  • @valsidalv 这是一个常规的 .Net 4.0 解决方案,它甚至比您正在使用的当前 .Net 版本还要旧。我不明白这是怎么“权力太大”。不同之处在于我在 .Net (WPF) 中使用了正确的类,而不是已弃用的类。
  • WPF world中的@valsidalv,那只是一个trivial thing,没有你想象的那么强大。

标签: c# .net winforms textbox


【解决方案1】:

您可以通过使用StringBuilder 而不是使用字符串连接来加快速度。

var results = new StringBuilder();
while (dbReader.Read())
{
    results.Append(dbReader[0].ToString());
}
txtDatabaseResults.Text = results.ToString();

使用string 和连接会给 GC 带来很大压力,尤其是在附加 7000 行文本的情况下。每次使用string += 时,CLR 都会创建一个新字符串实例,这意味着需要对旧的字符串实例(逐渐变大)进行垃圾回收。 StringBuilder 避免了这个问题。

请注意,将文本分配给TextBox 时仍然会有延迟,因为它需要刷新并显示该文本。 TextBox 控件没有针对这么多的文本进行优化,所以这可能是一个瓶颈。

至于将其推入后台线程 - 由于您使用的是 .NET 4.5,因此您可以使用新的异步支持来处理此问题。这可以通过将包含此代码的方法标记为async 并使用以下代码来实现:

string resultString = await Task.Run(()=>
{
    var results = new StringBuilder();
    while (dbReader.Read())
    {
        results.Append(dbReader[0].ToString());
    }
    return results.ToString();
});

txtDatabaseResults.Text = resultString;

【讨论】:

  • 并非如此,限制有时取决于 TextBox 本身,所有字符串都已在内存中,但需要 TextBox 很多时间来渲染 @987654333 @.
  • @KingKing 7000 行,你几乎可以保证 GC 压力。这将导致速度放缓 - 尽管理所当然,TextBox 可能仍然是最大的因素。
  • 这很有帮助。 StringBuilder 会影响文本框绘制文本的方式,还是只是更快地构建字符串?
  • @valsidalv 只是更快地构建字符串 - 我为您进行了另一个潜在的优化......但是,如果这没有帮助,下一步将是更好的控制。
  • 我现在想知道(在异步示例中)更新我的进度条的代码会去哪里。我已经有了文件中的总行数,但我需要获取当前行 - 一个 int,它会在 results.Append() 之后立即递增。
【解决方案2】:

使用StringBuilder

StringBuilder e = new StringBuilder();
while (dbReader.Read())
{
   e.Append(dbReader[0].ToString());
}
txtDatabaseResults.Text = e.ToString();

【讨论】:

    【解决方案3】:

    尽管建议使用并行的Thread,但从文件中提取行的方式存在某种缺陷。虽然每次连接 resulStringstring 都是不可变的,但实际上您创建了另一个(更大的)字符串。在这里,StringBuilder 非常有用:

    StringBuilder resultString = new StringBuilder ()
    while (dbReader.Read())
    {
       resultString = resultString.Append(dbReader[0].ToString());
    }
    txtDatabaseResults.Text = resultString;
    

    【讨论】:

      【解决方案4】:

      我在一次调用中用一个非常长的字符串(超过 200kB,从文件加载。我只是用我的字符串分配 TextBox 的 Text 属性)在单个调用中填充了一个常规 TextBox (multiline=true)。 它非常慢(> 1 秒)。 除了显示巨大的字符串之外,文本框还可以做任何事情。

      我使用了一个非常简单的技巧来提高性能:我将多行文本框替换为 RichTextBox(本机控件)。

      现在相同的加载是瞬时的,RichTextBox 的外观和行为与带有原始文本的 TextBox 完全相同(只要您没有对其进行调整)。最明显的区别是 RTB 默认没有上下文菜单。

      当然,这不是在所有情况下都可以解决的问题,也不是针对 OP 问题,但对我来说它工作得很好,所以我希望它可以帮助其他人在 Textbox 和大字符串的性能方面面临同样的问题。

      【讨论】:

        猜你喜欢
        • 2012-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-06
        • 2017-07-05
        • 1970-01-01
        相关资源
        最近更新 更多