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

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

问题描述:

我的应用程序使用了很多线程,每个线程都使用我的AddDetailLog函数在全局文本框中添加线程的进度,所以我可以按照每个线程的进度进行操作。这个函数每秒可以调用500次以上,当我使用VS2015 Profiler时,我已经看到使用我的CPU的50%是这个函数。当我加载超过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在我的全球形式。

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

感谢

+2

你可以创建一个缓冲区来存储消息(不显示它们),然后有一个计时器每隔1秒触发一次以将其附加到“TextBox”....或问自己,“我是否需要看到所有这些日志消息?“ –

首先,Control.Invoke()阻塞调用过程,最终击败你的后台线程的目的,因为他们最终会通过GDI消息泵同步。您可以使用BeginInvoke()而不是异步进行呼叫,从而允许您的后台进程继续。

其次,写入这样的速度一个TextBox控制是要你慢下来,因为任何改变TextBox.Text必火TextChanged,其中除其他事项外将重绘与更新的文本控制。每秒执行500次,特别是使用任何自定义TextChanged处理程序(如代码将文本框滚动到底部),并且您将会烧焦UI线程非常脆。

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

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