一.如何理解异步编程
使用 .NET 异步编程,在程序继续执行的同时对 .NET 类方法进行调用,直到进行指定的回调为止;
如果没有提供回调,则直到对调用的阻塞、轮询或等待完成为止。
例如,一个程序可以调用一个方法,该方法枚举一个较大的列表,同时主程序将继续执行。在完成枚举后,进行回调并由程序对它进行寻址。
二.使用异步编程的领域
文件IO 流IO 套接字IO
远程处理信道(HTTP、TCP)和代理
使用 ASP.NET 创建的 XML Web services
ASP.NET Web 窗体
使用 MessageQueue 类的消息队列
异步委托
三.如何进行进行异步调用?
.NET Framework 允许异步调用任何方法。
定义需要调用的方法具有相同签名的委托
公共语言运行库将自动为该委托定义具有适当签名的 BeginInvoke 和 EndInvoke 方法。
四.委托与传统的函数指针的区别
委托是安全的面向对象的函数指针,为了加深学员对此的理解,分别用C++实现一个函数指针和C#实现一个委托,见例1和例2.
五.Delegate类、MulticastDelegate和delegate关键字介绍
为了加深学员的理解,使用ILDASM反汇编工具查看例2生成的DLL的IL代码
重点是Invoke、BeginInvoke 和 EndInvoke方法以及参数的含义
六.IAsyncResult接口
IAsyncResult 接口用于监视和管理异步操作。该接口是从开始操作返回的并被传递到结束操作,以将开始操作和结束操作相关联。如果回调被
指定为开始操作的一部分,则 AsyncResult 被传递到回调。它的四个属性如下:
AsyncState :返回在开始操作方法调用中作为最后一个参数提供的对象。
AsyncWaitHandle :返回 WaitHandle,后者可用于执行 WaitHandle.WaitOne、WaitAny 或 WaitAll。
CompletedSynchronously :如果开始操作调用已同步完成,则 CompletedSynchronously 属性将被设置为 true。
IsCompleted :在服务器已处理完调用后,IsCompleted 属性将被设置为 true。
七.四种异步编程方法
调用BeginInvoke后,有四种选择:
(1)进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。 (见例3)
(2)使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后
调用 EndInvoke。(见例4)
(3)轮询由 BeginInvoke 返回的 IAsyncResult,确定异步调用何时完成,然后调用 EndInvoke。(见例5)
(4)将用于回调方法的委托传递给 BeginInvoke。该方法在异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。(见例6
)
注意:始终在异步调用完成后调用 EndInvoke。
八.Webservice异步调用、远程对象异步调用、异步Socket的实现,代码取自MSDN
九.代码部分
例(1)
////////////////////////////////////////
#include <iostream.h>
typedef int CFun(int);
void FunTest(CFun * f,int i)
{
cout<<f(i)<<endl;
}
int Fun1(int i)
{
return i;
}
int Fun2(int i,int j)
{
return i+j;
}
int main()
{
FunTest((CFun *)Fun1,5);
FunTest((CFun *)Fun2,3);//可以通过编译,运行时产生不可预知的结果
return 0;
}
///////////////////////////////////////
例(2)
///////////////////////////////////////
using System;
namespace DelegateTest
{
public delegate int MyDelegate1(int i);
public delegate int MyDelegate2(int i,int j);
public delegate int MyDelegate3(int i,int j,int k);
class ClassMain
{
[STAThread]
static void Main(string[] args)
{
ClassMain cm=new ClassMain();
MyDelegate1 md1=new MyDelegate1(cm.Fun1);
int n=md1(10);
Console.WriteLine(n);
MyDelegate2 md2=new MyDelegate2(cm.Fun2);
n=md2(10,100);
Console.WriteLine(n);
//错误的代码,委托和函数签名不匹配,不能通过编译
//md=new MyDelegate(cm.Fun2);
}
private int Fun1(int i)
{
return i;
}
private int Fun2(int i,int j)
{
return i+j;
}
}
}
///////////////////////////////////////
例(3)
///////////////////////////////////////
using System;
using System.Threading;
namespace AsyTest1
{
public delegate void MyDelegate();
class ClassMain
{
[STAThread]
static void Main(string[] args)
{
MyDelegate md=new MyDelegate(Fun);
IAsyncResult ar=md.BeginInvoke(null,null);
int i=1;
//调用线程模拟正在做一些操作
while(i<1000000000)
{
i+=2;
i-=1;
}
Console.WriteLine("调用线程的工作做完了,下面等待异步调用完成");
md.EndInvoke(ar);
Console.WriteLine("程序结束");
}
static void Fun()
{
//模拟正在进行一些耗时操作,比如检索文件
Thread.Sleep(10000);
Console.WriteLine("Fun执行完毕");
}
}
}
//////////////////////////////////////
例(4)
//////////////////////////////////////
using System;
using System.Threading;
namespace AsyTest2
{
public delegate int MyDelegate(int i,int j);
class ClassMain
{
[STAThread]
static void Main(string[] args)
{
MyDelegate md=new MyDelegate(Fun);
IAsyncResult ar=md.BeginInvoke(10,20,null,null);
//使用等待句柄
ar.AsyncWaitHandle.WaitOne();
Console.WriteLine("等待结束");
int k=md.EndInvoke(ar);
Console.WriteLine("程序结束,k={0}",k);
}
static int Fun(int i,int j)
{
//模拟正在进行一些耗时操作,比如检索文件
Thread.Sleep(10000);
Console.WriteLine("Fun执行完毕");
return i+j;
}
}
}
//////////////////////////////////////
例(5)
//////////////////////////////////////
using System;
using System.Threading;
namespace AsyTest3
{
public delegate int MyDelegate(int i,int j);
class ClassMain
{
[STAThread]
static void Main(string[] args)
{
MyDelegate md=new MyDelegate(Fun);
IAsyncResult ar=md.BeginInvoke(10,20,null,null);
while(ar.IsCompleted==false)
{
//模拟正在做一些其他操作
Console.WriteLine(".....");
Thread.Sleep(2000);
}
Console.WriteLine("轮询结束");
int k=md.EndInvoke(ar);
Console.WriteLine("程序结束,k={0}",k);
}
static int Fun(int i,int j)
{
//模拟正在进行一些耗时操作,比如检索文件
Thread.Sleep(10000);
Console.WriteLine("Fun执行完毕");
return i+j;
}
}
}
//////////////////////////////////////
例(6)
//////////////////////////////////////
using System;
using System.Threading;
namespace AsyTest4
{
public delegate int MyDelegate(int i,int j);
class ClassMain
{
[STAThread]
static void Main(string[] args)
{
MyDelegate md=new MyDelegate(Fun);
//启动异步调用,指定回调函数CallBack
IAsyncResult ar=md.BeginInvoke(10,20,new AsyncCallback(CallBack),md);
//主函数继续执行其他操作
Thread.Sleep(5000);
Console.WriteLine("主函数的操作完成");
//避免主函数在Fun之前结束
Console.ReadLine();
}
static int Fun(int i,int j)
{
//模拟正在进行一些耗时操作,比如检索文件
Thread.Sleep(10000);
return i+j;
}
static void CallBack(IAsyncResult ar)
{
//获取主函数中的md对象引用
MyDelegate md=(MyDelegate)ar.AsyncState;
int k=md.EndInvoke(ar);
Console.WriteLine("Fun执行完毕,回调函数执行,结果={0}",k);
}
}