V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
nimonew
V2EX  ›  Windows

#winform#子控件刷新时,主界面卡死,要如何解决

  •  
  •   nimonew · Mar 9, 2020 · 3210 views
    This topic created in 2252 days ago, the information mentioned may be changed or developed.

    在做一个日志工具 GUI,主界面上有一个 richtext 控件输出日志信息,当日志疯狂输出时,主界面就卡死了,有什么的解决方案呢? 日志是启用一个线程,线程中 Process 调用 cmd,委托事件输出日志。日志追加方法如下。我是才看了 3 天的 C#,网上资料太少了点

            public void AppendConsole(string log)
            {
    
                if (string.IsNullOrWhiteSpace(log)) return;
                //在 UI 线程中执行
                consolebox.BeginInvoke(new Action(() =>
                {
                    consolebox.AppendText(log);
                    consolebox.AppendText(Environment.NewLine);//追加换行符
                }));
    
            }
    
    17 replies    2020-03-10 15:34:06 +08:00
    ByteRan
        1
    ByteRan  
       Mar 9, 2020   ❤️ 1
    限流
    blueboyggh
        2
    blueboyggh  
       Mar 9, 2020
    貌似需要用 backgroundworker 吧
    mcdull619
        3
    mcdull619  
       Mar 9, 2020
    别在 UI 线程中输出 , 创建子线程做这些操作 .
    geelaw
        4
    geelaw  
       Mar 9, 2020   ❤️ 1
    首先,大量进行 AppendText 本来性能就不行,使用 #1 的思路,限制 append 的频率,一次 append 多条消息(先拼好再送去 AppendText )。另一个思路是使用性能更好的控件,例如这里完全没有体现为什么要用 RichText。

    @mcdull619 #3 是强行背诵式回答问题,对 UI 的变化只能在 UI 线程上进行。
    nimonew
        5
    nimonew  
    OP
       Mar 9, 2020
    @geelaw 好的谢谢,如果不用这个控件, 选用什么控件好一点,因为我不太了解
    nimonew
        6
    nimonew  
    OP
       Mar 9, 2020
    @blueboyggh 试过了,也是会卡
    Daming
        7
    Daming  
       Mar 9, 2020
    一个最简单的

    Task.Factory.StartNew(() =>
    {
    // 和 UI 无关的逻辑

    this.Invoke(new Action(()=>{
    //UI 逻辑操作
    }));

    }).ContinueWith(t =>
    {
    if (t.IsFaulted)
    {
    // 记录异常
    }
    });
    nimonew
        8
    nimonew  
    OP
       Mar 9, 2020
    @Daming 不是任务的问题,应该是 UI 刷新太频繁了
    ysc3839
        9
    ysc3839  
       Mar 9, 2020 via Android
    @geelaw > 对 UI 的变化只能在 UI 线程上进行。

    这似乎是不一定的? Windows UI 的多线程限制好像不那么严格。
    按照微软文档所说 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage
    If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure.
    看上去 Windows 会自动切到目标线程执行,不需要自己处理的。
    darktutu
        10
    darktutu  
       Mar 9, 2020
    最近搞过一次界面卡死的问题,你先降低更新的频率,不要那么频繁。
    nimonew
        11
    nimonew  
    OP
       Mar 9, 2020
    @darktutu 已经搞到 50ms 输出一次了
    geelaw
        12
    geelaw  
       Mar 9, 2020   ❤️ 1
    @ysc3839 WinForm 默认情况下会对每个 UI 变化进行检查,如果当前线程不是建立该 UI 对象的线程则直接抛出异常。

    你应该认为所有的 UI 对象都相当于一个 STA COM 对象,而 Windows 提供的 SendMessage 等 API 相当于是带有 marshalling 的,因此如果你尝试从另一个线程 SendMessage 到 UI 对象,就相当于你进行了正确的跨 apartment COM 调用。SetWindowText 最终也会变成 SendMessage,因此调用 Win32 API 会有正确的结果。

    然而这样随意的编程方式很危险——因为 SendMessage 自己会进行消息处理,你的 WndProc 必须是 reentrant 才行,大多数人写出来的都不是。WinForm 的做法就是默认不允许跨线程操作,程序员需要显式表达线程切换——好习惯从最开始就要培养。
    geelaw
        13
    geelaw  
       Mar 9, 2020
    @x537196 #5 最简单的想法是用不 rich 的 TextBox。
    darktutu
        14
    darktutu  
       Mar 9, 2020
    private void button1_Click(object sender, EventArgs e)
    {
    var task = new Task(() =>
    {
    var index = 1;
    while(true)
    {
    AppendConsole(index.ToString());
    index++;
    System.Threading.Thread.Sleep(50);
    }
    });
    task.Start();
    }
    public void AppendConsole(string log)
    {
    if (string.IsNullOrWhiteSpace(log)) return;
    //在 UI 线程中执行
    richTextBox1.BeginInvoke(new Action(() =>
    {
    richTextBox1.AppendText(log);
    richTextBox1.AppendText(Environment.NewLine);//追加换行符
    }));

    }

    兄弟,我这么跑也不会卡死啊?
    nimonew
        15
    nimonew  
    OP
       Mar 10, 2020
    @geelaw 用 richtextbox 是要用颜色标记一些信息出来
    nimonew
        16
    nimonew  
    OP
       Mar 10, 2020
    @darktutu 我开始设置的 sleep 是 2,然后还有一个内容变更事件没有处理
    neilq
        17
    neilq  
       Mar 10, 2020   ❤️ 1
    存在缓存里,每隔多少秒输出到 ui,或者每满多少兆输出到 ui,或者多种策略结合着来
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1412 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 64ms · UTC 17:12 · PVG 01:12 · LAX 10:12 · JFK 13:12
    ♥ Do have faith in what you're doing.