C#异步调用的好处和方法分享

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#异步调用的好处和方法分享相关的知识,希望对你有一定的参考价值。

参考技术A 程包括界面就不会死掉了。异步如何开始,好理解,现在我们讨论的是如何结束这个异步出来的新线程。
首先,异步出来的新线程,必须回收,不回收是浪费资源的可耻行为,.NET也是不允许的,所以你别想钻空子,俗话说,请神容易送神难,就是这个道理。下面你可以很容易想到,回收分为2种情况:主动回收和被动回收(当然,这是我自己的理解,微软可不是这么说的),主动回收就是,你去监视那个线程,并且等待,当异步方法完成了,就把异步线程回收,焦点回归主线程,实际上就是上篇文章《C#异步初步》的那种情况,BeginInvoke之后又EndInvoke,如果在EndInvoke的时候,该异步线程没有完成操作,那么整个程序,包括主线程,又在阻塞了,又会出现界面“死”的情况。要想解决这个问题,就使用“被动回收”方式,其中一个重要的办法就是“异步回调”。
核心有二:
A、
用回调函数(本例中为CallBackMethod),异步结束后,自动调用此回调函数。
B、
而不在主线程中手工等待异步结束,如上两例中在主线程中调用EndInvoke。此种方法,是在回调函数中调用EndInvoke的。
异步回调的大概流程是这样的:首先启动异步,启动参数加上异步结束时执行的方法,然后这个异步线程就不用管了,最后当这个异步线程自己完成工作了,就自动执行启动参数里的那个方法,这样确实很省心,可是代码写起来,就很复杂了。
下面是搜藏的代码:
复制代码代码如下:
//首先准备好,要进行异步的方法(能异步的,最好不多线程)
privatestringMethodName(intNum,outintNum2)

Num2=Num;
return"HelloWorld";

//程序终点
//异步完成时,执行的方法(回调方法),此方法只能有IAsyncResult一个参数,但是该参数几乎万能,可以传递object
privatevoidCallBackMethod(IAsyncResultar)

//从异步状态ar.AsyncState中,获取委托对象
DelegateNamedn=(DelegateName)ar.AsyncState;
//输出参数
inti;
//一定要EndInvoke,否则你的下场很惨
stringr=dn.EndInvoke(outi,ar);
MessageBox.Show("异步完成喽!i的值是"i.ToString()",r的值是"r);

//定义与方法同签名的委托
privatedelegatestringDelegateName(intNum,outintNum2);
//程序入口
privatevoidRun()

//实例化委托并初赋值
DelegateNamedn=newDelegateName(MethodName);
//输出参数
inti;
//实例化回调方法
//把AsyncCallback看成Delegate你就懂了,实际上AsyncCallback是一种特殊的Delegate,就像Event似的
AsyncCallbackacb=newAsyncCallback(CallBackMethod);
//异步开始
//如果参数acb换成null则表示没有回调方法
//最后一个参数dn的地方,可以换成任意对象,该对象可以被回调方法从参数中获取出来,写成null也可以。参数dn相当于该线程的ID,如果有多个异步线程,可以都是null,但是绝对不能一样,不能是同一个object,否则异常
IAsyncResultiar=dn.BeginInvoke(1,outi,acb,dn);
//去做别的事
//…………

//最后的结果应该是:i=1,r="HelloWorld"
//另外,如果可以,定义委托的时候可以选择不用过多的修饰:
///<summary>
///定义委托
///</summary>
///<returns></returns>
publicdelegateboolAsyncdelegate();
///<summary>
///Callbackmethodmusthavethesamesignatureasthe
///AsyncCallbackdelegate
///</summary>
///<paramname="ar"></param>
privatevoidCallbackMethod(IAsyncResultar)

//Retrievethedelegate.
Asyncdelegatedlgt=(Asyncdelegate)ar.AsyncState;
//CallEndInvoketoretrievetheresults.
dlgt.EndInvoke(ar);

//其他方法中调用:
//异步执行
//指定委托方法
Asyncdelegateisgt=newAsyncdelegate(icpInfo.Insert);
IAsyncResultar=isgt.BeginInvoke(newAsyncCallback(CallbackMethod),isgt);

C#异步调用四大方法详解

C#异步调用四大方法是什么呢?C#异步调用四大方法的使用是如何进行的呢?让我们首先了解下什么时候用到C#异步调用:

.NET Framework 允许您C#异步调用任何方法。定义与您需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名的 BeginInvoke 和 EndInvoke 方法。

BeginInvoke 方法用于启动C#异步调用。它与您需要异步执行的方法具有相同的参数,只不过还有两个额外的参数(将在稍后描述)。BeginInvoke 立即返回,不等待C#异步调用完成。BeginInvoke 返回 IasyncResult,可用于监视调用进度。

EndInvoke 方法用于检索C#异步调用结果。调用 BeginInvoke 后可随时调用 EndInvoke 方法;如果C#异步调用未完成,EndInvoke 将一直阻塞到C#异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。

注意   Visual Studio .NET 中的智能感知功能会显示 BeginInvoke 和 EndInvoke 的参数。如果您没有使用 Visual Studio 或类似的工具,或者您使用的是 C# 和 Visual Studio .NET,请参见异步方法签名获取有关运行库为这些方法定义的参数的描述。

本主题中的代码演示了四种使用 BeginInvoke 和 EndInvoke 进行C#异步调用的常用方法。调用了 BeginInvoke 后,可以:

· 进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。

· 使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后调用 EndInvoke。

· 轮询由 BeginInvoke 返回的 IAsyncResult,确定C#异步调用何时完成,然后调用 EndInvoke。

· 将用于回调方法的委托传递给 BeginInvoke。该方法在C#异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。

警告:始终在C#异步调用完成后调用 EndInvoke。

测试方法和异步委托

四个示例全部使用同一个长期运行的测试方法 TestMethod。该方法显示一个表明它已开始处理的控制台信息,休眠几秒钟,然后结束。TestMethod 有一个 out 参数(在 Visual Basic 中为 ByRef),它演示了如何将这些参数添加到 BeginInvoke 和 EndInvoke 的签名中。您可以用类似的方式处理 ref 参数(在 Visual Basic 中为 ByRef)。

下面的代码示例显示 TestMethod 以及代表 TestMethod 的委托;若要使用任一示例,请将示例代码追加到这段代码中。

注意   为了简化这些示例,TestMethod 在独立于 Main() 的类中声明。或者,TestMethod 可以是包含 Main() 的同一类中的 static 方法(在 Visual Basic 中为 Shared)。

  1. using System;  
    using System.Threading;   
     
    public class AsyncDemo {  
    // The method to be executed asynchronously.  
    //  
    public string TestMethod(  
    int callDuration, out int threadId) {  
    Console.WriteLine("Test method begins.");  
    Thread.Sleep(callDuration);  
    threadId = AppDomain.GetCurrentThreadId();  
    return "MyCallTime was " + callDuration.ToString();  
    }  
    }  
     
    // The delegate must have the same signature as the method  
    // you want to call asynchronously.  
    public delegate string AsyncDelegate(  
    int callDuration, out int threadId);  
       
     
    using System;  
    using System.Threading;   
     
    public class AsyncDemo {  
    // The method to be executed asynchronously.  
    //  
    public string TestMethod(  
    int callDuration, out int threadId) {  
    Console.WriteLine("Test method begins.");  
    Thread.Sleep(callDuration);  
    threadId = AppDomain.GetCurrentThreadId();  
    return "MyCallTime was " + callDuration.ToString();  
    }  
    }  
     
    // The delegate must have the same signature as the method  
    // you want to call asynchronously.  
    public delegate string AsyncDelegate(  
    int callDuration, out int threadId); 

     

C#异步调用四大方法之使用 EndInvoke 等待异步调用

异步执行方法的最简单方式是以 BeginInvoke 开始,对主线程执行一些操作,然后调用 EndInvoke。EndInvoke 直到C#异步调用完成后才返回。这种技术非常适合文件或网络操作,但是由于它阻塞 EndInvoke,所以不要从用户界面的服务线程中使用它。

  1. public class AsyncMain {  
    static void Main(string[] args) {  
    // The asynchronous method puts the thread id here.  
    int threadId;  
     
    // Create an instance of the test class.  
    AsyncDemo ad = new AsyncDemo();  
     
    // Create the delegate.  
    AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);  
         
    // Initiate the asychronous call.  
    IAsyncResult ar = dlgt.BeginInvoke(3000,   
    out threadId, null, null);  
     
    Thread.Sleep(0);  
    Console.WriteLine("Main thread {0} does some work.",  
    AppDomain.GetCurrentThreadId());  
     
    // Call EndInvoke to Wait for   
    //the asynchronous call to complete,  
    // and to retrieve the results.  
    string ret = dlgt.EndInvoke(out threadId, ar);  
     
    Console.WriteLine("The call executed on thread {0},   
    with return value \"{1}\".", threadId, ret);  
    }  
    } 

     

C#异步调用四大方法之使用 WaitHandle 等待异步调用

等待 WaitHandle 是一项常用的线程同步技术。您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 属性来获取 WaitHandle。C#异步调用完成时会发出 WaitHandle 信号,而您可以通过调用它的 WaitOne 等待它。

如果您使用 WaitHandle,则在C#异步调用完成之后,但在通过调用 EndInvoke 检索结果之前,可以执行其他处理。

  1. public class AsyncMain {  
    static void Main(string[] args) {  
    // The asynchronous method puts the thread id here.  
    int threadId;  
     
    // Create an instance of the test class.  
    AsyncDemo ad = new AsyncDemo();  
     
    // Create the delegate.  
    AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);  
         
    // Initiate the asychronous call.  
    IAsyncResult ar = dlgt.BeginInvoke(3000,   
    out threadId, null, null);  
     
    Thread.Sleep(0);  
    Console.WriteLine("Main thread {0} does some work.",  
    AppDomain.GetCurrentThreadId());  
     
    // Wait for the WaitHandle to become signaled.  
    ar.AsyncWaitHandle.WaitOne();  
     
    // Perform additional processing here.  
    // Call EndInvoke to retrieve the results.  
    string ret = dlgt.EndInvoke(out threadId, ar);  
     
    Console.WriteLine("The call executed on thread {0},   
    with return value \"{1}\".", threadId, ret);  
    }  
    } 

     

C#异步调用四大方法之轮询异步调用完成

您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 属性来发现C#异步调用何时完成。从用户界面的服务线程中进行C#异步调用时可以执行此操作。轮询完成允许用户界面线程继续处理用户输入。

  1. public class AsyncMain {  
    static void Main(string[] args) {  
    // The asynchronous method puts the thread id here.  
    int threadId;  
     
    // Create an instance of the test class.  
    AsyncDemo ad = new AsyncDemo();  
     
    // Create the delegate.  
    AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);  
         
    // Initiate the asychronous call.  
    IAsyncResult ar = dlgt.BeginInvoke(3000,   
    out threadId, null, null);  
     
    // Poll while simulating work.  
    while(ar.IsCompleted == false) {  
    Thread.Sleep(10);  
    }  
     
    // Call EndInvoke to retrieve the results.  
    string ret = dlgt.EndInvoke(out threadId, ar);  
     
    Console.WriteLine("The call executed on thread {0},  
     with return value \"{1}\".", threadId, ret);  
    }  
    } 

     

C#异步调用四大方法之异步调用完成时执行回调方法

如果启动异步调用的线程不需要处理调用结果,则可以在调用完成时执行回调方法。回调方法在 ThreadPool 线程上执行。

要使用回调方法,必须将代表该方法的 AsyncCallback 委托传递给 BeginInvoke。也可以传递包含回调方法将要使用的信息的对象。例如,可以传递启动调用时曾使用的委托,以便回调方法能够调用 EndInvoke。

  1. public class AsyncMain {  
    // Asynchronous method puts the thread id here.  
    private static int threadId;  
     
    static void Main(string[] args) {  
    // Create an instance of the test class.  
    AsyncDemo ad = new AsyncDemo();  
     
    // Create the delegate.  
    AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);  
         
    // Initiate the asychronous call.  Include an AsyncCallback  
    // delegate representing the callback method, and the data  
    // needed to call EndInvoke.  
    IAsyncResult ar = dlgt.BeginInvoke(3000,  
    out threadId,   
    new AsyncCallback(CallbackMethod),  
    dlgt );  
     
    Console.WriteLine("Press Enter to close application.");  
    Console.ReadLine();  
    }  
     
    // Callback method must have the same signature as the  
    // AsyncCallback delegate.  
    static void CallbackMethod(IAsyncResult ar) {  
    // Retrieve the delegate.  
    AsyncDelegate dlgt = (AsyncDelegate) ar.AsyncState;  
     
    // Call EndInvoke to retrieve the results.  
    string ret = dlgt.EndInvoke(out threadId, ar);  
     
    Console.WriteLine("The call executed on thread {0},  
     with return value \"{1}\".", threadId, ret);  
    }  
    }  

     

C#异步调用四大方法的基本内容就向你介绍到这里,希望对你了解和学习C#异步调用有所帮助。

以上是关于C#异步调用的好处和方法分享的主要内容,如果未能解决你的问题,请参考以下文章

C# 异步方法加await调用不就变成同步方法了吗

C#同步调用异步方法

捕获调用异步方法C#的异常[重复]

C# 使用多个异步方法

C# 同步调用 异步调用 异步回调 多线程的作用

从 F# 调用 C# 异步方法会导致死锁