当同步调用委托时,Invoke()方法直接对当前线程调用目标方法;
当异步调用委托时,CLR将对请求进行排队并立即返回到调用方,将对来自线程池的线程调用该目标方法,提交请求的原始线程继续与目标方法并行执行,该目标方法是对线程池线程运行的.
1)、BeginInvoke()方法
BeginInvoke()方法启动异步调用,它与需要异步执行的方法具有相同的参数。
另外,还有两个可选参数:第一个参数是AsyncCallback委托,该委托引用在异步调用完成时要调用的方法;第二个参数是用户定义的对象,该对象可向回调方法传递信息;
BeginInvoke立即返回,不等待异步调用完成;
BeginInvoke返回IAsyncResult,这个结果可用于监视异步调用的进度;
2)、EndInvoke()方法
EndInvoke()方法检索异步调用的结果;
在调用BeginInvoke()方法后,可以随时调用EndInvoke()方法,如果异步调用尚未完成,则EndInvoke()方法将一直阻止调用线程,直到异步调用完成后才允许调用线程执行;
EndInvoke()的参数需要异步执行的方法的out和ref参数以及由BeginInvoke()返回的IAsyncResult。
delegate int MyDel(int a, int b);
static void Main(string[] args)
{
MyDel del = new MyDel(AddFun);
del.Invoke(2, 2);
while (true) //主线程一直工作
{
Console.WriteLine("主线程{0}在工作", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
}
}
static int AddFun(int a, int b)
{
Console.WriteLine("工作线程{0}在跑着,值为{1}", Thread.CurrentThread.ManagedThreadId, a + b);
Thread.Sleep(5000); //这里我们让线程睡眠5秒,看主线程是否被阻塞
return a + b;
}
这里停顿了5秒之后...
上面证明了这个委托会阻塞主线程...
那么如何不让它阻塞呢!想到了多线程,
但是Thread里面的委托 参数ThreadStart和ParameterThreadStart中的委托都没有返回值类型(void)
那么我们就引入主题,异步委托---
//AsyncCallBack为回调函数,委托执行完以后让回调函数去处理结果,这样就不会阻塞主线程了。
实际也就是委托调执行以后,又一个委托把结果进行处理
delegate int MyDel(int a, int b);
static void Main(string[] args)
{
MyDel del = new MyDel(AddFun);
//del.Invoke(2, 2);
del.BeginInvoke(1, 2, new AsyncCallback(AscCallBack), null);
while (true)
{
Console.WriteLine("主线程{0}在工作", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
}
}
static int AddFun(int a, int b)
{
Console.WriteLine("工作线程{0}在跑着,值为{1}", Thread.CurrentThread.ManagedThreadId, a + b);
Thread.Sleep(5000);
return a + b;
}
static void AscCallBack(IAsyncResult result)
{
AsyncResult aResult = (AsyncResult)result;
MyDel del = (MyDel)aResult.AsyncDelegate;
int addResult = del.EndInvoke(result);
Console.WriteLine("我是主线程还是子线程?噢原来是{0}", Thread.CurrentThread.ManagedThreadId);
}
执行结果:
到5秒的时候
我们可以看到,主线程没有被阻塞,而且工作线程和主线程不是同一个线程。
其实异步委托是在线程池内获取到一个线程,也是一种多线程的体现。
那么什么时候用多线程,什么时候用异步委托呢? 上面说过多线程的委托没有返回值,而异步委托可以自己随便定义。
当需要执行I/O操作时,使用异步操作比使用线程+同步I/O操作更合适。I/O操作不仅包括了直接的文件、网络的读写,还包括数据库操作、Web Service、HttpRequest以及.Net Remoting等跨进程的调用。
而线程的适用范围则是那种需要长时间CPU运算的场合,例如耗时较长的图形处理和算法执行。但是往往由于使用线程编程的简单和符合习惯,所以很多朋友往往会使用线程来执行耗时较长的I/O操作。这样在只有少数几个并发操作的时候还无伤大雅,如果需要处理大量的并发操作时就不合适了。