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

在对程序优化过程中,我们往往对循环体有着刻骨的仇恨,因为它对性能的损耗尤其之大,比如如下例程,是个简单的循环例程,全部执行需要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)完成退出当前方法后,未执行的异步委托会自动取消委托。
这样的话比起线程来说,就有很多好处了,因为发出线程是很难取消的。

更多请看

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值