.NET中实现异步操作的三种方式:
异步委托、用BackgroundWorker组件、显式使用System.Threading.Thread
上述三种技术中核心都是使用线程,各有其适合的使用场所,其中前两种较为方便,适合完成单任务的异步操作,但第三种扩展性、灵活性最高,下面会各个介绍。
Tip:Sytsem.Windows.Forms.Timer组件并不提供多线程操作的功能,其是利用应用程序的idle moment触发其Tick事件完成相应的操作,操作的执行完全同一主线程中执行,这样UI更新、同步不是问题,但同时当你在Tick事件处理中完成time-consuming性操作时将会是问题(如非用户界面友好性等)。
.NET中提供了几种Timer,其中有于其他线程完成操作的(即多线程),可参见:http://msdn.microsoft.com/msdnmag/issues/04/02/TimersinNET
.NET中提供了几种Timer,其中有于其他线程完成操作的(即多线程),可参见:http://msdn.microsoft.com/msdnmag/issues/04/02/TimersinNET
public delegate int doSomeDele(int para);//定义委托
doSomeDele dsd = new doSomeDele(obj.method);//实例化委托
//开始异步调用并注册callback函数,于异步线程中执行obj.method
dsd.BeginInvoke(para,new AsyncCallBck(myCallBack),dsd);
private void myCallBack(IasyncResult async)//于异步线程中执行
{
//取回传入的原委托实例
doSomeDele dosome = (doSomeDele)async.AsyncState;
//取委托调用的所得的结果
int ret = dosome.EndInvoke(async);
}
原理:异步委托的实现不会创建新的线程,其所用的线程将由clr所管理的线程池(单cpu计算机最多25线程)维护,超过线程池容量的线程需求将等待
doSomeDele dsd = new doSomeDele(obj.method);//实例化委托
//开始异步调用并注册callback函数,于异步线程中执行obj.method
dsd.BeginInvoke(para,new AsyncCallBck(myCallBack),dsd);
private void myCallBack(IasyncResult async)//于异步线程中执行
{
//取回传入的原委托实例
doSomeDele dosome = (doSomeDele)async.AsyncState;
//取委托调用的所得的结果
int ret = dosome.EndInvoke(async);
}
原理:异步委托的实现不会创建新的线程,其所用的线程将由clr所管理的线程池(单cpu计算机最多25线程)维护,超过线程池容量的线程需求将等待
异步委托的调用在涉及更新winApp的ui时(也即主线程外的线程更新ui),将由control的InvokeReqired属性(如果当前code不是running在control被创建的线程其值为true)和Invoke方法(在ui的线程上触发方法)完成。
//允许任意签名的委托
control.Invoke(new customDelegate(…),new object[]{…});
//.net提供无参的委托
control.Invoke(new MethodInvoker(…))
原理:control.Invoke的执行将首先检查其windows handle是否存在,若存在,Invoke方法将用win32 api 的GetWindowThreadProcessId()为control获取thread id,并与当前执行线程的id –GetCurrentThreadId()-比较以决定是否需要marshalling(不等,则需要此操作)。若其windows handle不存在,Invoke将向上回溯在其parent(or parent’parent etc)的寻找,因此一个动态创建的control,其上激发的Invoke将比期望的执行略慢,当然你可以直接调用其父控件的Invoke,或在调用前检查control.Handle是否存在。Marshal 用户method将由Invoke用win api PostMessage在消息队列在为ui thread post一个消息,直到主线程的idle moment将处理此消息(建议将主线程中rocessor-intensive任务在其他线程中完成)
关于control.Invoke的更多:http://weblogs.asp.net/justin_rogers/articles/126345.aspx
control.Invoke(new customDelegate(…),new object[]{…});
//.net提供无参的委托
control.Invoke(new MethodInvoker(…))
原理:control.Invoke的执行将首先检查其windows handle是否存在,若存在,Invoke方法将用win32 api 的GetWindowThreadProcessId()为control获取thread id,并与当前执行线程的id –GetCurrentThreadId()-比较以决定是否需要marshalling(不等,则需要此操作)。若其windows handle不存在,Invoke将向上回溯在其parent(or parent’parent etc)的寻找,因此一个动态创建的control,其上激发的Invoke将比期望的执行略慢,当然你可以直接调用其父控件的Invoke,或在调用前检查control.Handle是否存在。Marshal 用户method将由Invoke用win api PostMessage在消息队列在为ui thread post一个消息,直到主线程的idle moment将处理此消息(建议将主线程中rocessor-intensive任务在其他线程中完成)
关于control.Invoke的更多:http://weblogs.asp.net/justin_rogers/articles/126345.aspx
BackgroundWorker组件的使用:
backgroundWorker.RunWorkerAsync(customObject);
//当backgroundWorker获得线程后将触发DoWork事件,所以可以注册其事件处理
//其中DoWorkEventArgs的Argument可获取传入的customObject,Result属性用
//于保存获取的结果,此中执行任务
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
//上述方法执行完毕backgroundWorker将触发RunWorkerCompleted事件
//可于此进行UI相关操作,其中RunWorkerCompletedEventArgs的Result
//属性用于获取上述方法中的结果
void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
//当backgroundWorker获得线程后将触发DoWork事件,所以可以注册其事件处理
//其中DoWorkEventArgs的Argument可获取传入的customObject,Result属性用
//于保存获取的结果,此中执行任务
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
//上述方法执行完毕backgroundWorker将触发RunWorkerCompleted事件
//可于此进行UI相关操作,其中RunWorkerCompletedEventArgs的Result
//属性用于获取上述方法中的结果
void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
另外BackgroundWorker还可提供report process功能,但除非自定义接口进行包装,否则将把线程任务和ui紧密耦合,当然亦可使用Thread取完成此功能。
System.Threading.Thread自不必多说(可说的太多了),完成.net的多线程编程,详细的多线程编程可参见具体书籍,如c# thread handbook等,等以后用的多了再总结。