先推荐阅读下面的资料:
MSDN:异步编程设计模式
IBM developerworks: 使用异步 I/O 大大提高应用程序的性能
参考博文:
1、正确使用异步操作
5、异步编程
.NET Framework 为异步操作提供两种设计模式:
1、使用 IAsyncResult 对象的异步操作。
2、使用事件的异步操作。
IAsyncResult接口类型
public interface IAsyncResult
{
// 摘要:
// 获取用户定义的对象,它限定或包含关于异步操作的信息。
//
// 返回结果:
// 用户定义的对象,它限定或包含关于异步操作的信息。
object AsyncState { get ; }
//
// 摘要:
// 获取用于等待异步操作完成的 System.Threading.WaitHandle。
//
// 返回结果:
// 用于等待异步操作完成的 System.Threading.WaitHandle。
WaitHandle AsyncWaitHandle { get ; }
//
// 摘要:
// 获取异步操作是否同步完成的指示。
//
// 返回结果:
// 如果异步操作同步完成,则为 true;否则为 false。
bool CompletedSynchronously { get ; }
//
// 摘要:
// 获取异步操作是否已完成的指示。
//
// 返回结果:
// 如果操作完成则为 true,否则为 false。
bool IsCompleted { get ; }
}
下面是使用 IAsyncResult 对象的测试代码。
class Program
{
static void Main( string [] args)
{
Fun1();
Console.ReadLine();
}
private static int threadId;
// 阻塞等待 使用 EndInvoke 等待异步调用
static void Fun1()
{
// 创建示例类的实例。
AsyncDemo ad = new AsyncDemo();
// 创建委托
AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
// 委托在这里开始异步调用。
IAsyncResult ar = dlgt.BeginInvoke( 5000 , out threadId, null , null );
// 人为的线程阻塞。
Thread.Sleep( 0 );
Console.WriteLine( " 主线程 {0}开始工作 " ,Thread.CurrentThread.ManagedThreadId);
// 委托开始EndInvoke调用,这个过程会使主线程等待异步调用完成并返回结果。
string ret = dlgt.EndInvoke( out threadId, ar);
Console.WriteLine( " 异步线程 {0},返回值 / " { 1 }/ " . " , threadId, ret);
Console.WriteLine( " 主线程{0}结束工作 " , Thread.CurrentThread.ManagedThreadId);
}
// 阻塞等待 使用 WaitHandle 等待异步调用
static void Fun2()
{
AsyncDemo ad = new AsyncDemo();
AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
IAsyncResult ar = dlgt.BeginInvoke( 5000 , out threadId, null , null );
Thread.Sleep( 0 );
Console.WriteLine( " 主线程 {0}开始工作 " , Thread.CurrentThread.ManagedThreadId);
// 主线程在这里等待,直到异步线程执行完。
ar.AsyncWaitHandle.WaitOne();
// 和前一方案的区别在于,你可以在异步调用完成后,获取异步调用返回值之前
// 在这里做点任何你想作的事。
// 调用EndInvoke获取异步调用的返回结果.
string ret = dlgt.EndInvoke( out threadId, ar);
Console.WriteLine( " 异步线程 {0},返回值 / " { 1 }/ " . " , threadId, ret);
Console.WriteLine( " 主线程{0}结束工作 " , Thread.CurrentThread.ManagedThreadId);
}
// 轮询状态 轮询异步调用完成
static void Fun3()
{
AsyncDemo ad = new AsyncDemo();
AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
IAsyncResult ar = dlgt.BeginInvoke( 5000 , out threadId, null , null );
Console.WriteLine( " 主线程 {0}开始工作 " , Thread.CurrentThread.ManagedThreadId);
// 这里每隔10毫秒就检测(轮询)一下异步执行的状态,
// 直到异步调用完成,IsCompleted的值变为ture为止。
while (ar.IsCompleted == false )
{
Thread.Sleep( 10 );
}
// 还记得微软的那个善意的提醒吗?虽然IsCompleted为true了,
// 我们还是调用一下EndInvoke,来获取返回值。
string ret = dlgt.EndInvoke( out threadId, ar);
Console.WriteLine( " 异步线程 {0},返回值 / " { 1 }/ " . " , threadId, ret);
Console.WriteLine( " 主线程{0}结束工作 " , Thread.CurrentThread.ManagedThreadId);
}
// 通知机制 异步调用完成时执行回调方法
static void Fun4()
{
AsyncDemo ad = new AsyncDemo();
AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
// 注意第三个参数,这就是我们要用到的回调方法。
// 第四个参数更为有趣,它可以是任何Object对象,这里它就是
// 执行异步调用的委托本身,把委托本身传递进去的原因在下面可以看到。
Console.WriteLine( " 主线程 {0}开始工作 " , Thread.CurrentThread.ManagedThreadId);
IAsyncResult ar = dlgt.BeginInvoke( 5000 , out threadId, new AsyncCallback(CallbackMethod), dlgt);
Console.WriteLine( " 主线程 {0}结束工作 " , Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}
// 回调函数必须严格的遵照AsyncCallback委托的签名。
static void CallbackMethod(IAsyncResult ar)
{
// 在这里,上面那个dlgt作为参数的作用得到了体现,原来它就是为了完成对EndInvoke的调用啊。
AsyncDelegate dlgt = (AsyncDelegate)ar.AsyncState;
// 通过对EndInvoke的调用获取返回值。
string ret = dlgt.EndInvoke( out threadId, ar);
Console.WriteLine( " 异步线程 {0},返回值 / " { 1 }/ " . " , threadId, ret);
}
}
// 使用异步编程模型
public class AsyncDemo
{
public string TestMethod( int callDuration, out int threadId)
{
Console.WriteLine( " 异步方法开始工作 " );
Thread.Sleep(callDuration);
threadId = Thread.CurrentThread.ManagedThreadId;
return " 异步方法执行时间 " + callDuration.ToString();
}
}
执行结果:
Fun1--------------------
异步方法开始工作
主线程 10开始工作
异步线程 7,返回值 "异步方法执行时间 5000".
主线程10结束工作
Fun2---------------------
异步方法开始工作
主线程 10开始工作
异步线程 7,返回值 "异步方法执行时间 5000".
主线程10结束工作
Fun3---------------------
主线程 10开始工作
异步方法开始工作
异步线程 7,返回值 "异步方法执行时间 5000".
主线程10结束工作
Fun4---------------------
主线程 10开始工作
主线程 10结束工作
异步方法开始工作
异步线程 7,返回值 "异步方法执行时间 5000".
--------------------------
工作当中有一个调用ActiveMQ的产品,每天大概是上万的消息。压力也不是很大。最近总是出现调用MQ阻塞的情况。负责MQ的同事也没有找到原因。
我是想寻找一个消息队列的代替品。 上面的第四个方法,异步线程不阻塞调用线程,当然调用线程也无需处理调用结果,貌似可以作为一个代替方案。