同步调用
委托的Invoke方法用来进行同步调用。同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行。
异步调用
异步调用不阻塞线程,而是把调用塞到线程池中,程序主线程或UI线程可以继续执行。我的理解是虽然表面上没有新开启线程,但实际上异步调用时CLR自动为你开启了一个新线程。委托的异步调用通过Beginxxx和Endxxx来实现。这种方式称为APM 异步编程模型。
Beginxxx : 开始一个异步的请求,调用线程池中一个线程来执行
返回IAsyncResult 对象(异步的核心). IAsyncResult 简单的说,他存储异步操作的状态信息的一个接口,也可以用他来结束当前异步。
注意: Beginxxx和Endxxx必须成对调用.即使不需要返回值,但Endxxx还是必须调用,否则可能会造成内存泄漏。
(1)定义委托:
public delegate string MyDelegate(int abc);
那么对应的BeginInvoke和EndInvoke如下:
public virtual IAsyncResult BeginInvoke(int abc, AsyncCallBack callback, object asyncState) 和 public virtual string EndInvoke(IAsyncResult asyncResult)
MyDelegate m_MyDelegate = fun
fun与m_MyDelegate 具有相同签名的方法
(3)调用:IAsyncResult m_AsyncResult = m_MyDelegate.BeginInvoke(1, onComplete, asyncState);
此时CLR会打开一个新的线程去异步执行委托的方法fun,当fun执行结束时就回到调用方线程并调用onComplete。
AsyncCallback 也是一个委托,它的参数永远都是IAsyncResult ,而且这个参数就是BeginInvoke里的asyncState参数。
//回调方法onComplete方法的定义如下:
public void onComplete(IAsyncResult m_AsyncResult )
{
...... //其它处理代码
string result = EndInvoke(m_AsyncResult );
...... //其它处理代码
}
BeginInvoke方法前部分的参数是用来给调用它的委托对象所代理的那个方法传递参数即传给fun,最后两个参数为可选,第一个是用来声明回调函数的方法名,第二个参数是 "传递额外的参数",在这里是传给onComplete。通过BeginInvoke方法的最后一个参数可以在调用方和回调函数之间传递状态,因为他本身是Object对象,我们可以传递任何对象。
回调方法的参数永远都是IAsyncResult ,没办法直接给回调方法传递自己想要的参数,所以只能通过asyncState来间接的传递给回调方法。
在回调函数中如何取得这个参数呢?AsyncResult 类封装的AsyncState属性保存了BeginInvoke 的最后一个参数,我们可以通过它得到。关于这一部分的知识可以看我另一篇博客AsyncResult 类的使用。
EndInvoke方法是在回调方法里被调用来获取执行结果。
注意EndInvoke和回调函数接收的参数都是BeginInvoke的返回值m_AsyncResult ,而EndInvoke的返回值正是委托方法的返回类型(在这里就是string)。
下面MSDN的代码示例演示如何使用 Dns 类中的异步方法来检索用户指定的计算机的域名系统 (DNS) 信息。 此示例创建一个引用 ProcessDnsInformation 方法的 AsyncCallback 委托。 对各个针对 DNS 信息发出的异步请求,将分别调用一次此方法。
/*
The following example demonstrates using asynchronous methods to
get Domain Name System information for the specified host computers.
This example uses a delegate to obtain the results of each asynchronous
operation.
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Specialized;
using System.Collections;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class UseDelegateForAsyncCallback
{
static int requestCounter;
static ArrayList hostData = new ArrayList();
static StringCollection hostNames = new StringCollection();
static void UpdateUserInterface()
{
// Print a message to indicate that the application
// is still working on the remaining requests.
Console.WriteLine("{0} requests remaining.", requestCounter);
}
public static void Main()
{
// Create the delegate that will process the results of the
// asynchronous request.
AsyncCallback callBack = new AsyncCallback(ProcessDnsInformation);//定义回调函数
string host;
do
{
Console.Write(" Enter the name of a host computer or <enter> to finish: ");
host = Console.ReadLine();
if (host.Length > 0)
{
// Increment the request counter in a thread safe manner.
Interlocked.Increment(ref requestCounter);
// Start the asynchronous request for DNS information.
Dns.BeginGetHostEntry(host, callBack, host);
}
} while (host.Length > 0);
// The user has entered all of the host names for lookup.
// Now wait until the threads complete.
while (requestCounter > 0)
{
UpdateUserInterface();
}
// Display the results.
for (int i = 0; i< hostNames.Count; i++)
{
object data = hostData [i];
string message = data as string;
// A SocketException was thrown.
if (message != null)
{
Console.WriteLine("Request for {0} returned message: {1}",
hostNames[i], message);
continue;
}
// Get the results.
IPHostEntry h = (IPHostEntry) data;
string[] aliases = h.Aliases;
IPAddress[] addresses = h.AddressList;
if (aliases.Length > 0)
{
Console.WriteLine("Aliases for {0}", hostNames[i]);
for (int j = 0; j < aliases.Length; j++)
{
Console.WriteLine("{0}", aliases[j]);
}
}
if (addresses.Length > 0)
{
Console.WriteLine("Addresses for {0}", hostNames[i]);
for (int k = 0; k < addresses.Length; k++)
{
Console.WriteLine("{0}",addresses[k].ToString());
}
}
}
}
// The following method is called when each asynchronous operation completes.
static void ProcessDnsInformation(IAsyncResult result)
{
string hostName = (string) result.AsyncState;//传值
hostNames.Add(hostName);
try
{
// Get the results.
IPHostEntry host = Dns.EndGetHostEntry(result);//取结果
hostData.Add(host);
}
// Store the exception message.
catch (SocketException e)
{
hostData.Add(e.Message);
}
finally
{
// Decrement the request counter in a thread-safe manner.
Interlocked.Decrement(ref requestCounter);
}
}
}
}