有关对耗时很大循环进行并行化优化的探讨 之一:并发搜索的处理

 

   在对程序优化过程中,我们往往对循环体有着刻骨的仇恨,因为它对性能的损耗尤其之大,比如如下例程,是个简单的循环例程,全部执行需要30秒以上(痛苦):

  public enum HandleRst
    {
        完成,
        错误_手术刀忘肚子里了,
        失败_药物过敏,
        失败_家属不签字,
    }

   public  class Obj_Fath
    { 
        private int _SonLen;

        public int SonLen
        {
            get { return _SonLen; }
            set { _SonLen = value; }
        }

      public Obj_Fath(string myt)
      {
            _T = myt;
            _SonObjList = new List<Obj_Son>();
            for (int i = 0; i < 1500; i++)
            {
                Obj_Son p = new Obj_Son(this );
                _SonObjList.Add(p);
            }
      }

     public  HandleRst  DoAsyncHandle()
      {
          HandleRst rst= HandleRst.完成;

          if (_SonObjList.Count > 0)
            {
                foreach (Obj_Son son in _SonObjList)
                {
                    HandleRst r = ComputeEachSon(son);
                    if (r != HandleRst.完成)
                    {
                        _ThisHandleRst = r;
                        break;
                    }
                }               
            }
            return rst ;
        }

        HandleRst ComputeEachSon(Obj_Son sonObj)
        {
            Thread.Sleep(1);
            return sonObj.DoCompute();
        }
  }

  public   class Obj_Son
    {
        Obj_Fath _ObjFath;
        public Obj_Son(Obj_Fath fathObj)
        {
            _ObjFath = fathObj;
        }

        public HandleRst DoCompute()
        {
            int len=0;
            lock (_ObjFath )
            {
              _ObjFath.SonLen++;
              len =_ObjFath .SonLen ;
            }

            Thread.Sleep (1);
            
            if (len  >1300)
            {
                return HandleRst.失败_家属不签字;
            }
            return HandleRst.完成;
        }
    }

 但如何优化它呢,我们很容易想到要对循环体进行并发执行,即


foreach (Obj_Son son in _SonObjList)
{
  Thread t =new Thread(ParameterThreadStart(ThreadCompute));
  t.Start(son);
}        
 但这里带来了几个问题:
 1) 如何获得ComputeEachSon方法的结果?
 2) 如何在返回不为“完成”时立即退出循环?
 貌似使用简单的多线程并发无法解决这个问题。

于是,我们想到了采用异步方法,改进后,执行的时间缩减到了6秒,效果还是不错的,附上简单的异步处理代码供大家研究改进。
        bool _Tok;
        ManualResetEvent _FinEvent;
        private HandleRst _ThisHandleRst;
        private int _HandleCount;

        public  HandleRst  DoAsyncHandle()
        {
           _ThisHandleRst  = HandleRst.完成;

            _FinEvent = new ManualResetEvent(false);
            _HandleCount = 0;

            if (_SonObjList.Count > 0)
            {
                foreach (Obj_Son son in _SonObjList)
                {
                    if (_Tok)
                        break;
                    HasSonComputingHandler h = new HasSonComputingHandler(ComputeEachSon);
                    HandleRst r = HandleRst.完成;
                    AsyncCallback t = new AsyncCallback(HandleCallBack);
                    h.BeginInvoke(son, t, h);
                }                
                _FinEvent.WaitOne();
            }
            return _ThisHandleRst ;
        }

     
       void HandleCallBack(IAsyncResult iR)
       {          
           if (_Tok)
               return;

           HasSonComputingHandler u = (HasSonComputingHandler)iR.AsyncState;
           HandleRst r = u.EndInvoke(iR);
           lock (this)
           {
               if (r != HandleRst.完成)
               {
                   _ThisHandleRst = r;
                   _FinEvent.Set();
                   _Tok = true;
               }

               _HandleCount++;
               if (_HandleCount == _SonObjList.Count)
               {
                   _ThisHandleRst = r;
                   _FinEvent.Set();
                   _Tok = true;
               }              
           }         
       }

 

试了一下异步操作循环体,发现了一个有趣的现象:
 执行
  Obj_Fath t = new Obj_Fath("hello");

  HandleRst u=  t.DoAsyncHandle();
  MessageBox.Show("\n计数HandleCount:" +t.HandleCount .ToString ()+"\n计数Sonlen:"+t.SonLen .ToString () +"\n" );

 发现 HandeCount值在1298~1302之间
           SonLen值在1306~1312之间。
如果顺序执行循环体,程序是在1300次循环时退出, 这说明
1)程序注册了2500个异步委托后,就直接进入阻塞等待状态。
2)完成退出当前方法后,未执行的异步委托会自动取消委托。
这样的话比起线程来说,就有很多好处了,因为发出线程是很难取消的。

更多请看

 有关对耗时很大循环进行并行化优化的探讨之二:多重循环任务的并发处理 .

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值