使用publisher模式控制频繁的UI输出,避免Winform界面假死

http://www.cnblogs.com/Charltsing/p/publisher.html

最近测试task并发任务的效率与线程池的区别,发现了另外一个问题。task建立任务的速度很快,输出到UI的信息过频,导致UI假死。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private void TestMakeTasks(object obj)
    {
        string msg = "";
         
        //循环创建task
        for (int i = 0; i < 3000; i++)
        {
            //主线程(winform)--子线程(Thread)--工作线程(task)
            //不能在循环里面连续访问UI,会造成UI来不及处理,导致假死。               
            Task<string> tt = Task.Factory.StartNew<string>(test, i);
            tt.ContinueWith((t) =>
            {
                if (t.IsFaulted)
                {
                    string msgexcep = (string.Format("I have observed a {0}", t.Exception.InnerException.GetType().Name));
                    Interlocked.Increment(ref responsecount);
                    Interlocked.Decrement(ref threadscount);
                }
            });
            //Thread.Sleep(1);  //避免过快发送UI更新请求,导致假死。
            msg = " 已发送请求数:" + requestcount.ToString() + " 已完成请求数:" + responsecount.ToString();
 
            //输出线程建立信息给UI,过频会导致假死。<br>                PublishStatus(msg);
 
            Interlocked.Increment(ref threadscount);
            Interlocked.Increment(ref requestcount);
            if (_isStop)
            {
                PublishMessage("正在退出...\r\n");
                break;
            }
        }
        PublishMessage("发送完毕,请等待线程运行完毕!\r\n");
        while (responsecount < requestcount)
        {
            Thread.Sleep(300);
            msg = "!已发送请求数:" + requestcount.ToString() + " 已完成请求数:" + responsecount.ToString();
            PublishStatus(msg);
        }
        _isRunning = false;
        PublishMessage("\r\n全部线程运行完毕!\r\n");
    }

  为了解决这个问题,考虑使用publisher模式控制UI输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Publisher
    {
        public bool isbusy = false;   //标志
        public delegate void PublishEventHander(object sender, PubEventArgs e);
 
        public event PublishEventHander PublishMessage;
        public event PublishEventHander PublishStatus;
 
        //声明一个可重写的OnPublish的保护函数
        protected virtual void OnPublishMessage(PubEventArgs e)
        {
            if (PublishMessage != null)
            {
                //Sender = this,也就是Publisher
                this.PublishMessage(this, e);
            }
        }
        protected virtual void OnPublishStatus(PubEventArgs e)
        {
            if (PublishStatus != null)
            {
                //Sender = this,也就是Publisher
                this.PublishStatus(this, e);
            }
        }
 
        /// <summary>
        /// 触发publish message事件
        /// </summary>
        public void IssueMessage(string message)
        {
            OnPublishMessage(new PubEventArgs(message));
        }
 
        /// <summary>
        /// 触发publish status事件
        /// </summary>
        public void IssueStatus(string message)
        {
            if (!isbusy) OnPublishStatus(new PubEventArgs(message));        }
    }

  同时,在UI输出部分,使用Invoke来阻止更多的UI操作(不能使用BeginInvoke)。

1
2
3
4
5
6
7
8
9
10
11
private void WriteStatus(string msg)
    {
        if (this.lblStatus.InvokeRequired)
        {
            Invoke(cdWriteStatus, msg);
        }
        else
        {
            UpdatelblMethod(msg);
        }
    }

  

大致思路是 task创立任务之后,发给publisher一个通知(使用IssueStatus函数),publisher通过OnPublishStatus事件通知给Subscriber,UI界面作为订阅者通过设置publisher的busy状态使得publisher取消后面多余的输出事件。

 

有问题请联系QQ 564955427

posted @   Charltsing  阅读(776)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示