2

I have a .NET 4.5 WinForm program that queries a text-based database using ODBC. I then want to display every result in a multiline textbox and I want to do it in the quickest way possible.
The GUI does not have to be usable during the time the textbox is being updated/populated. However, it'd be nice if I could update a progress bar to let the user know that something is happening - I believe a background worker or new thread/task is necessary for this but I've never implemented one.

I initially went with this code and it was slow, as it drew out the result every line before continuing to the next one.

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

This was significantly faster.

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

But there is a generous wait time before the textbox comes to life so I want to know if the operation can be even faster. Right now I'm fetching about 7,000 lines from the file and I don't think it's necessary to switch to AvalonEdit (correct me if my way of thinking is wrong, but I would like to keep it simple and use the built-in textbox).

4

4 回答 4

6

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

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;
于 2013-10-15T17:32:40.977 回答
3

使用StringBuilder

StringBuilder e = new StringBuilder();
while (dbReader.Read())
{
   e.Append(dbReader[0].ToString());
}
txtDatabaseResults.Text = e.ToString();
于 2013-10-15T17:33:17.727 回答
1

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

StringBuilder resultString = new StringBuilder ()
while (dbReader.Read())
{
   resultString = resultString.Append(dbReader[0].ToString());
}
txtDatabaseResults.Text = resultString;
于 2013-10-15T17:35:36.707 回答
1

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

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

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

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

于 2017-08-09T14:15:03.587 回答