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

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

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

    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,过频会导致假死。
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输出

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)。

    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 on 2015-09-14 07:54 Charltsing 阅读(...) 评论(...) 编辑 收藏

导航