优化调用日志记录功能 - 多线程

时间:2017-03-15 16:50:28

标签: c# multithreading optimization

我的应用程序使用很多线程,每个线程使用我的AddDetailLog函数在全局textBox中添加线程的进度,所以我可以跟踪每个线程的进展情况。这个函数可以每秒调用超过500次,当我使用VS2015 Profiler时,我发现这个函数使用了50%的CPU。当我加载超过150个线程时,我的CPU处于100%,所以我真的需要优化这个功能。

使用多线程优化的功能:

public void AddDetailLog(string text)
    {
        if(Program.SHOWDETAILSLOG)
        {
            if (this.textBox_log.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(AddDetailLog);
                this.Invoke(d, new object[] { text });
            }
            else
                this.textBox_log.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "] - " + text + Environment.NewLine);
        }
    }

因为多线程的事情,我需要检查我的textBox是否需要调用,因为所有线程(不是backgroundWorker)都在我的全局表单上的同一个textBox上运行。

如果有人想要优化这个功能,我会很高兴听到它。

由于

1 个答案:

答案 0 :(得分:3)

首先,Control.Invoke()会阻止调用进程,最终会破坏后台线程的用途,因为它们最终会通过GDI消息泵同步。您可以使用BeginInvoke()异步进行调用,从而允许后台进程继续。

其次,以该速率写入TextBox控件会降低你的速度,因为对TextBox.Text的任何更改都会触发TextChanged,其中包括重新绘制控件的对象更新后的文字。每秒执行500次,特别是使用任何自定义TextChanged处理程序(如代码将文本框滚动到底部),并且您将对UI线程进行烧焦,非常脆。

相反,为什么不让你的记录器将条目写入更简单的内存中对象,然后在表单上执行Timer以检索,连接并在TextBox控件中显示这些消息?考虑到高并发性,我建议使用ConcurrentQueue<string>。您的后台工作人员执行“TryAdd”调用以将日志条目排入队列,然后您的UI Timer.Tick处理程序使用TryTake将它们出列,并以更友好的UI方式将它们附加到TextBox(例如,在附加到10之前,可以将10个批次中的条目连接起来文本框)。

最后,TextBox的内容越长,渲染所需的时间就越长,因为TextBox必须计算字符串的显示大小才能呈现滚动条并显示应该实际显示的字符串部分。我会在30k左右的字符后截断日志显示的“后端”。为了避免丢失可能有价值的信息,相同的处理程序可以将消息传递给StreamWriter,将所有内容写入文件;您可以在此处添加另一级别的异步处理,以保持UI响应。

相关问题