MSDN异步编程概述 C#bitman的专栏博客园.docx
《MSDN异步编程概述 C#bitman的专栏博客园.docx》由会员分享,可在线阅读,更多相关《MSDN异步编程概述 C#bitman的专栏博客园.docx(6页珍藏版)》请在冰豆网上搜索。
MSDN异步编程概述C#bitman的专栏博客园
MSDN-异步编程概述[C#]-bitman的专栏-博客园
.NETFramework允许您异步调用任何方法。
定义与您需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名的BeginInvoke和EndInvoke方法。
BeginInvoke方法用于启动异步调用。
它与您需要异步执行的方法具有相同的参数,只不过还有两个额外的参数(将在稍后描述)。
BeginInvoke立即返回,不等待异步调用完成。
BeginInvoke返回IasyncResult,可用于监视调用进度。
EndInvoke方法用于检索异步调用结果。
调用BeginInvoke后可随时调用EndInvoke方法;如果异步调用未完成,EndInvoke将一直阻塞到异步调用完成。
EndInvoke的参数包括您需要异步执行的方法的out和ref参数(在VisualBasic中为<Out>ByRef和ByRef)以及由BeginInvoke返回的IAsyncResult。
注意VisualStudio.NET中的智能感知功能会显示BeginInvoke和EndInvoke的参数。
如果您没有使用VisualStudio或类似的工具,或者您使用的是C#和VisualStudio.NET,请参见异步方法签名获取有关运行库为这些方法定义的参数的描述。
本主题中的代码演示了四种使用BeginInvoke和EndInvoke进行异步调用的常用方法。
调用了BeginInvoke后,可以:
·进行某些操作,然后调用EndInvoke一直阻塞到调用完成。
·使用IAsyncResult.AsyncWaitHandle获取WaitHandle,使用它的WaitOne方法将执行一直阻塞到发出WaitHandle信号,然后调用EndInvoke。
·轮询由BeginInvoke返回的IAsyncResult,确定异步调用何时完成,然后调用EndInvoke。
·将用于回调方法的委托传递给BeginInvoke。
该方法在异步调用完成后在ThreadPool线程上执行,它可以调用EndInvoke。
警告始终在异步调用完成后调用EndInvoke。
测试方法和异步委托
四个示例全部使用同一个长期运行的测试方法TestMethod。
该方法显示一个表明它已开始处理的控制台信息,休眠几秒钟,然后结束。
TestMethod有一个out参数(在VisualBasic中为<Out>ByRef),它演示了如何将这些参数添加到BeginInvoke和EndInvoke的签名中。
您可以用类似的方式处理ref参数(在VisualBasic中为ByRef)。
下面的代码示例显示TestMethod以及代表TestMethod的委托;若要使用任一示例,请将示例代码追加到这段代码中。
注意为了简化这些示例,TestMethod在独立于Main()的类中声明。
或者,TestMethod可以是包含Main()的同一类中的static方法(在VisualBasic中为Shared)。
usingSystem;
usingSystem.Threading;publicclassAsyncDemo{
//Themethodtobeexecutedasynchronously.
//
publicstringTestMethod(intcallDuration,outintthreadId){
Console.WriteLine("Testmethodbegins.");
Thread.Sleep(callDuration);
threadId=AppDomain.GetCurrentThreadId();
return"MyCallTimewas"+callDuration.ToString();
}
}//Thedelegatemusthavethesamesignatureasthemethod
//youwanttocallasynchronously.
publicdelegatestringAsyncDelegate(intcallDuration,outintthreadId);
usingSystem;
usingSystem.Threading;publicclassAsyncDemo{
//Themethodtobeexecutedasynchronously.
//
publicstringTestMethod(intcallDuration,outintthreadId){
Console.WriteLine("Testmethodbegins.");
Thread.Sleep(callDuration);
threadId=AppDomain.GetCurrentThreadId();
return"MyCallTimewas"+callDuration.ToString();
}
}//Thedelegatemusthavethesamesignatureasthemethod
//youwanttocallasynchronously.
publicdelegatestringAsyncDelegate(intcallDuration,outintthreadId);
使用EndInvoke等待异步调用
异步执行方法的最简单方式是以BeginInvoke开始,对主线程执行一些操作,然后调用EndInvoke。
EndInvoke直到异步调用完成后才返回。
这种技术非常适合文件或网络操作,但是由于它阻塞EndInvoke,所以不要从用户界面的服务线程中使用它。
publicclassAsyncMain{
staticvoidMain(string[]args){
//Theasynchronousmethodputsthethreadidhere.
intthreadId;//Createaninstanceofthetestclass.
AsyncDemoad=newAsyncDemo();//Createthedelegate.
AsyncDelegatedlgt=newAsyncDelegate(ad.TestMethod);
//Initiatetheasychronouscall.
IAsyncResultar=dlgt.BeginInvoke(3000,
outthreadId,null,null);Thread.Sleep(0);
Console.WriteLine("Mainthread{0}doessomework.",
AppDomain.GetCurrentThreadId());//CallEndInvoketoWaitfortheasynchronouscalltocomplete,
//andtoretrievetheresults.
stringret=dlgt.EndInvoke(outthreadId,ar);Console.WriteLine("Thecallexecutedonthread{0},withreturnvalue\"{1}\".",threadId,ret);
}
}
使用WaitHandle等待异步调用
等待WaitHandle是一项常用的线程同步技术。
您可以使用由BeginInvoke返回的IAsyncResult的AsyncWaitHandle属性来获取WaitHandle。
异步调用完成时会发出WaitHandle信号,而您可以通过调用它的WaitOne等待它。
如果您使用WaitHandle,则在异步调用完成之后,但在通过调用EndInvoke检索结果之前,可以执行其他处理。
publicclassAsyncMain{
staticvoidMain(string[]args){
//Theasynchronousmethodputsthethreadidhere.
intthreadId;//Createaninstanceofthetestclass.
AsyncDemoad=newAsyncDemo();//Createthedelegate.
AsyncDelegatedlgt=newAsyncDelegate(ad.TestMethod);
//Initiatetheasychronouscall.
IAsyncResultar=dlgt.BeginInvoke(3000,
outthreadId,null,null);Thread.Sleep(0);
Console.WriteLine("Mainthread{0}doessomework.",
AppDomain.GetCurrentThreadId());//WaitfortheWaitHandletobecomesignaled.
ar.AsyncWaitHandle.WaitOne();//Performadditionalprocessinghere.
//CallEndInvoketoretrievetheresults.
stringret=dlgt.EndInvoke(outthreadId,ar);Console.WriteLine("Thecallexecutedonthread{0},withreturnvalue\"{1}\".",threadId,ret);
}
}
轮询异步调用完成
您可以使用由BeginInvoke返回的IAsyncResult的IsCompleted属性来发现异步调用何时完成。
从用户界面的服务线程中进行异步调用时可以执行此操作。
轮询完成允许用户界面线程继续处理用户输入。
publicclassAsyncMain{
staticvoidMain(string[]args){
//Theasynchronousmethodputsthethreadidhere.
intthreadId;//Createaninstanceofthetestclass.
AsyncDemoad=newAsyncDemo();//Createthedelegate.
AsyncDelegatedlgt=newAsyncDelegate(ad.TestMethod);
//Initiatetheasychronouscall.
IAsyncResultar=dlgt.BeginInvoke(3000,
outthreadId,null,null);//Pollwhilesimulatingwork.
while(ar.IsCompleted==false){
Thread.Sleep(10);
}//CallEndInvoketoretrievetheresults.
stringret=dlgt.EndInvoke(outthreadId,ar);Console.WriteLine("Thecallexecutedonthread{0},withreturnvalue\"{1}\".",threadId,ret);
}
}
异步调用完成时执行回调方法
如果启动异步调用的线程不需要处理调用结果,则可以在调用完成时执行回调方法。
回调方法在ThreadPool线程上执行。
要使用回调方法,必须将代表该方法的AsyncCallback委托传递给BeginInvoke。
也可以传递包含回调方法将要使用的信息的对象。
例如,可以传递启动调用时曾使用的委托,以便回调方法能够调用EndInvoke。
publicclassAsyncMain{
//Asynchronousmethodputsthethreadidhere.
privatestaticintthreadId;staticvoidMain(string[]args){
//Createaninstanceofthetestclass.
AsyncDemoad=newAsyncDemo();//Createthedelegate.
AsyncDelegatedlgt=newAsyncDelegate(ad.TestMethod);
//Initiatetheasychronouscall.IncludeanAsyncCallback
//delegaterepresentingthecallbackmethod,andthedata
//neededtocallEndInvoke.
IAsyncResultar=dlgt.BeginInvoke(3000,
outthreadId,
newAsyncCallback(CallbackMethod),
dlgt);Console.WriteLine("PressEntertocloseapplication.");
Console.ReadLine();
}
//Callbackmethodmusthavethesamesignatureasthe
//AsyncCallbackdelegate.
staticvoidCallbackMethod(IAsyncResultar){
//Retrievethedelegate.
AsyncDelegatedlgt=(AsyncDelegate)ar.AsyncState;//CallEndInvoketoretrievetheresults.
stringret=dlgt.EndInvoke(outthreadId,ar);Console.WriteLine("Thecallexecutedonthread{0},withreturnvalue\"{1}\".",threadId,ret);
}
}