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