当需要更新太快,太多的数据不响应的用户界面 [英] Unresponsive UI when too fast and too much data needs to be updated

查看:73
本文介绍了当需要更新太快,太多的数据不响应的用户界面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了一个控制记录来自不同的线程消息屏幕。它采用丰富的文本框,显示格式化的文本。



当有20个线程其中追加的邮件每隔200-250ms主UI变得没有反应了一段时间,该消息后等待被处理的UI再次开始响应。当正在运行的线程窗口的移动不顺畅。



信息写入到丰富的文本框与锁同步。



你能提出以提高性能?我打算跑100个线程。






下面是我的代码。我的控制台输出(S)重定向到它,它会记录这回事,并显示在格式化形式的丰富文本框内的一切。

 公共无效RedirectStandardOutput()
{
Console.SetOut(ConsoleStream);

System.Diagnostics.Debug.Listeners.Add(新System.Diagnostics.TextWriterTraceListener(Console.Out));
System.Diagnostics.Debug.AutoFlush = TRUE;
}

在控制台重定向所有Console.WriteLine(喇嘛喇嘛); 。被写入屏幕






 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;使用System.Windows.Forms的
;使用CoreLib.Parsers
;

命名空间ConsoleWidget
{
公共类ConsoleStream:System.IO.TextWriter
{
私人只读对象_textBoxLock =新的对象();

公共RichTextBox的文本框{搞定;组; }
公开名单<&的TextFormat GT; TextFormatList {搞定;组; }

公共BOOL AUTOCLEAR {搞定;组; }
公众诠释AutoClearLength {搞定;组; }
公共BOOL自动保存{搞定;组; }
公共字符串AutoSaveDir {搞定;组; }


公共ConsoleStream()
{
TextFormatList =新的List<&的TextFormat GT;();
}

公共无效AppendText通过(字符串文本)
{
如果(文本框== NULL)回报;

VAR正文长度= TextBox.TextLength;

如果(AUTOCLEAR&安培;&安培;正文长度> AutoClearLength)
{
如果(自动保存)
{
VAR DIR =的String.Format(@ {0} \ {1} \ {2},Environment.CurrentDirectory,AutoSaveDir,CoreLib.Extensions.DateTimeExtensions.DateTimeNowDir);

如果
System.IO.Directory.CreateDirectory(DIR)(System.IO.Directory.Exists(DIR)!);

VAR路径=的String.Format(@{0} \ {1} .LOG,DIR CoreLib.Extensions.DateTimeExtensions.GetDateTimeNowFileName);

TextBox.SaveFile(路径);
}

TextBox.Clear();
}

TextBox.AppendText(文本);

//设置文本格式。
的foreach(在TextFormatList VAR的textFormat)
{
INT beginIndex;
INT长度;

如果(textFormat.GetFormatProperties(文字,出beginIndex,出长度))
{
// RichTextBox的计算换行符\r\\\
,这是双字符作为单个字符。
//原因选择中移开始。下面的线数将beginIndex前的​​\r字符。
变种leftText = text.Substring(0,beginIndex);
VAR newLineCount = leftText.Count(C =以及c =='\r');

TextBox.SelectionStart =正文长度+ beginIndex - newLineCount;
TextBox.SelectionLength =长度;
如果(!textFormat.Color.IsEmpty)
TextBox.SelectionColor = textFormat.Color;
如果(textFormat.Font!= NULL)
TextBox.SelectionFont = textFormat.Font;
}
}

TextBox.ScrollToCaret();
}

公共无效清除()
{
锁(_textBoxLock)
{
TextBox.Clear();
}
}

公众诠释正文长度
{
得到
{
锁(_textBoxLock)
{
返回TextBox.TextLength;
}
}
}

公共无效另存为(字符串路径)
{
锁(_textBoxLock)
{
TextBox.SaveFile(路径);
}
}

公众覆盖编码编码
{
{返回Encoding.Default; }
}

公共覆盖无效写入(字符串值)
{
如果(文本框== NULL)回报;

变种行动=(动作)(()=> AppendText通过(值));

锁(_textBoxLock)
{
如果(TextBox.InvokeRequired)
TextBox.BeginInvoke(动作);
,否则
动作();
}
}

公共覆盖无效的WriteLine()
{
写(新行);
}

公共覆盖无效的WriteLine(字符串值)
{
写(值);
的WriteLine();
}
}
}


解决方案

让你的工作线程的数据添加到某种队列/列表,然后让主线程的新数据存储每一秒/半秒增加了一批新的数据(调整,以适应你的进程)。



基本的东西像这样将可能被罚款:

 公共类数据存储< ; T> {
私有对象_lock =新的对象();
私有列表< T> _data =新的List< T>();
公共无效添加(T数据){
锁(_lock){
_data.Add(数据);
}
}

公共T [] TakeWork(){
T []的结果;
锁(_lock){
结果= _data.ToArray();
_data.Clear();
}
返回结果;
}
}



只需创建一个数据存储,让你的工作线程使用添加功能添加工作中显示然后执行



在_dataStore.TakeWork

 的foreach(VAR S( )){
richTextBox.AppendText(多个);
}




在System.Windows.Forms的。计时器事件。你可能会想修剪丰富的文本框的文本以及虽然因为你的应用程序将开始放缓,如果你只是一味地抽数据整天......


I made a control to log messages from different threads to screen. It uses rich text box to display formatted text.

When there are 20 threads which append their messages every 200-250ms the main UI becomes unresponsive for some time and after the messages waiting are processed the UI starts to response again. When the threads are running the moving of the window is not smooth.

Message writing to rich text box is synchronised with locks.

What can you suggest to improve the performance? I'm planning to run 100 threads.


Here is my code. I redirect the console output(s) to it and it logs everything that's going on and displays in formatted form inside a rich text box.

public void RedirectStandardOutput()
        {
            Console.SetOut(ConsoleStream);

            System.Diagnostics.Debug.Listeners.Add(new System.Diagnostics.TextWriterTraceListener(Console.Out));
            System.Diagnostics.Debug.AutoFlush = true;
        }

After the console is redirected all Console.WriteLine("bla bla"); is written to screen.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CoreLib.Parsers;

namespace ConsoleWidget
{
    public class ConsoleStream : System.IO.TextWriter
    {
        private readonly object _textBoxLock = new object();

        public RichTextBox TextBox { get; set; }
        public List<TextFormat> TextFormatList { get; set; }

        public bool AutoClear { get; set; }
        public int AutoClearLength { get; set; }
        public bool AutoSave { get; set; }
        public string AutoSaveDir { get; set; }


        public ConsoleStream()
        {
            TextFormatList = new List<TextFormat>();
        }

        public void AppendText(string text)
        {
            if (TextBox == null) return;

            var textLength = TextBox.TextLength;

            if (AutoClear && textLength > AutoClearLength)
            {
                if (AutoSave)
                {
                    var dir = string.Format(@"{0}\{1}\{2}", Environment.CurrentDirectory, AutoSaveDir, CoreLib.Extensions.DateTimeExtensions.DateTimeNowDir);

                    if (!System.IO.Directory.Exists(dir))
                        System.IO.Directory.CreateDirectory(dir);

                    var path = string.Format(@"{0}\{1}.log", dir, CoreLib.Extensions.DateTimeExtensions.GetDateTimeNowFileName);

                    TextBox.SaveFile(path);
                }

                TextBox.Clear();
            }

            TextBox.AppendText(text);

            // Format text.
            foreach (var textFormat in TextFormatList)
            {
                int beginIndex;
                int length;

                if (textFormat.GetFormatProperties(text, out beginIndex, out length))
                {
                    // RichTextBox counts newline "\r\n" which is double char as single char.
                    // Causes shifting in selection starts. The lines below count the "\r" chars before the beginIndex.
                    var leftText = text.Substring(0, beginIndex);
                    var newLineCount = leftText.Count(c => c == '\r');

                    TextBox.SelectionStart = textLength + beginIndex - newLineCount;
                    TextBox.SelectionLength = length;
                    if (!textFormat.Color.IsEmpty)
                        TextBox.SelectionColor = textFormat.Color;
                    if (textFormat.Font != null)
                        TextBox.SelectionFont = textFormat.Font;
                }
            }

            TextBox.ScrollToCaret();
        }

        public void Clear()
        {
            lock (_textBoxLock)
            {
                TextBox.Clear();
            }
        }

        public int TextLength
        {
            get
            {
                lock (_textBoxLock)
                {
                    return TextBox.TextLength;
                }
            }
        }

        public void SaveAs(string path)
        {
            lock (_textBoxLock)
            {
                TextBox.SaveFile(path);
            }
        }

        public override Encoding Encoding
        {
            get { return Encoding.Default; }
        }

        public override void Write(string value)
        {
            if (TextBox == null) return;

            var action = (Action)(() => AppendText(value));

            lock (_textBoxLock)
            {
                if (TextBox.InvokeRequired)
                    TextBox.BeginInvoke(action);
                else
                    action();
            }
        }

        public override void WriteLine()
        {
            Write(NewLine);
        }

        public override void WriteLine(string value)
        {
            Write(value);
            WriteLine();
        }
    }
}

解决方案

Have your worker threads add their data to some sort of queue/list and then have the main thread add a batch of new data from the store of new data every second/half second (tune to fit your process).

Something basic like this would probably be fine:

    public class DataStore<T>{
    private object _lock = new object();
    private List<T> _data = new List<T>();
    public void Add(T data){
        lock (_lock){
            _data.Add(data);
        }
    }

    public T[] TakeWork(){
        T[] result; 
        lock (_lock){
            result= _data.ToArray(); 
            _data.Clear();
        }
        return result;
    }
}

Just create a DataStore and have your work threads use the Add function to add work to be displayed then do

      foreach (var s in _dataStore.TakeWork()){
            richTextBox.AppendText(s);                  
        }

in a System.Windows.Forms.Timer event. You will probably want to trim the rich text box text as well though since your app will start to slow down if you just keep pumping data in all day....

这篇关于当需要更新太快,太多的数据不响应的用户界面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆