学习笔记:同步和异步调用delegate
每次我们创建一个delegate类型的时候,系统会为我们创建一个继承自MulticastDelegate的类。假设我们创建一个如下的delegate:
public delegate int BinaryOp(int x, int y);
public sealed class BinaryOp : System.MulticastDelegate
{
public BinaryOp(object target, uint functionAddress);
public void Invoke(int x, int y);
public IAsyncResult BeginInvoke(int x, int y, AsyncCallback cb, object state);
public int EndInvoke(IAsyncResult result);
}
实际上,当我们通过声明一个delegate并调用该方法的时候,我们是调用Invoke方法。系统在执行完该方法之后再返回,整个过程是一个同步调用,系统在执行delegate代码的时候会等待该部分执行完再继续,而且所有这些代码的执行是在同一个线程里面。
如果我们要通过异步调用来执行delegate的话,则需要使用BeginInvoke和EndInvoke方法,这样delegate代码是在另外一个线程中执行,这样我们的代码就是一个多线程执行的过程。
搬用书上的一个例子:
我们在程序中创建一个delegate BinaryOp,然后在Main中间调用它。在Main和delegate中分别打印该执行代码所在线程ID:
代码
2 using System;
3
4 namespace SyncDelegate
5 {
6 public delegate int BinaryOp(int x, int y);
7
8 class Program
9 {
10 static void Main(string[] args)
11 {
12 Console.WriteLine("***** Synch Delegate Review *****");
13
14 // Print out the ID of the executing thread.
15 Console.WriteLine("Main() invoked on thread {0}.",
16 Thread.CurrentThread.ManagedThreadId);
17
18 // Invoke Add() in a synchronous manner.
19 BinaryOp b = new BinaryOp(Add);
20
21 // Could also write b.Invoke(10, 10);
22 int answer = b(10, 10);
23
24 // These lines will not execute until
25 // the Add() method has completed.
26 Console.WriteLine("Doing more work in Main()!");
27 Console.WriteLine("10 + 10 is {0}.", answer);
28 Console.ReadLine();
29 }
30
31 #region Very time consuming addition!
32 static int Add(int x, int y)
33 {
34 // Print out the ID of the executing thread.
35 Console.WriteLine("Add() invoked on thread {0}.",
36 Thread.CurrentThread.ManagedThreadId);
37
38 // Pause to simulate a lengthy operation.
39 Thread.Sleep(5000);
40 return x + y;
41 }
42 #endregion
43 }
44 }
如果查看输出的结果我们可以看到Main输出的线程Id和delegate中的Id是一样的,而且系统会等大概5秒的样子然后显示计算结果,这说明他们是在同一个线程中执行的。
那么我们用什么法子来启动一个异步的线程来调用这个delegate呢?我们可以仔细看看生成的类中间的BeginInvoke和EndInvoke方法。
public IAsyncResult BeginInvoke(int x, int y, AsyncCallback cb, object state);
public int EndInvoke(IAsyncResult result);
一、异步调用的方式
如果我们将原来同步调用的方式作如下的修改:
代码
{
public delegate int BinaryOp(int x, int y);
class Program
{
static void Main(string[] args)
{
Console.WriteLine("**** Synch Delegate Review ****");
Console.WriteLine("Main() invoked on thread {0}.",
Thread.CurrentThread.ManagedThreadId);
// Invoke add() in a synchronous manner
BinaryOp b = new BinaryOp(Add);
IAsyncResult iftAR = b.BeginInvoke(10, 10, null, null);
int answer = b.EndInvoke(iftAR);
Console.WriteLine("10 + 10 is {0}.", answer);
Console.ReadLine();
}
static int Add(int x, int y)
{
Console.WriteLine("Add() invoked on thread: {0}",
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(5000);
return x + y;
}
}
}
通过调用BeginInvoke方法,启动异步调用,在返回的结果我们也可以看到,Add方法执行的线程Id是不同的。如果要获取函数调用返回的结果,我们就通过EndInvoke方法以BeginInvoke方法的结果作为参数。
二、IAsyncResult
IAsyncResult是一个定义成如下形式的接口:
代码
2 public interface IAsyncResult
3 {
4 // Properties
5 object AsyncState { get; }
6 WaitHandle AsyncWaitHandle { get; }
7 bool CompletedSynchronously { get; }
8 bool IsCompleted { get; }
9 }
它包含了当前执行状况信息。可以传递给其他函数提供这些执行信息。
三、AsyncCallback
BeginInvoke方法和生成的Invoke方法的差别在于后面多了两个参数,AsyncCallback和object.
如果我们去查MSDN或者用reflector查看源代码就发现AsyncCallback是一个定义成如下形式的delegate:
就像其本身名字所定义的那样,它是用于回调的,反馈给调用该方法自己执行状况的。比如说,当我们启动一个异步delegate执行的时候,我们想要知道它执行的怎么样了,什么时候执行完。我们可以定义一个AsyncCallback类型的方法,在异步delegate执行的时候调用该方法来通知调用线程。
而对于object参数,这是用来提供一些自定义的数据的。
看如下示例:
代码
2 {
3 public delegate int BinaryOp(int x, int y);
4
5 class Program
6 {
7 static void Main(string[] args)
8 {
9 Console.WriteLine("**** AsyncCallback Delegate Example ****");
10 Console.WriteLine("Main() invoked on thread {0}.",
11 Thread.CurrentThread.ManagedThreadId);
12
13 BinaryOp b = new BinaryOp(Add);
14 IAsyncResult iftAR = b.BeginInvoke(10, 10, AddComplete, "Main() thanks you for adding these numbers.");
15 Console.WriteLine("Doing more things in Main");
16 Console.ReadLine();
17
18 }
19
20 static void AddComplete(IAsyncResult itfAR)
21 {
22 Console.WriteLine("AddComplete() invoked on thread {0}.",
23 Thread.CurrentThread.ManagedThreadId);
24 Console.WriteLine("Your addition is complete.");
25
26 // get the result
27 AsyncResult ar = (AsyncResult)itfAR;
28 BinaryOp b = (BinaryOp)ar.AsyncDelegate;
29 Console.WriteLine("10 + 10 is {0}.",
30 b.EndInvoke(itfAR));
31 string msg = (string)itfAR.AsyncState;
32 Console.WriteLine(msg);
33 }
34
35 static int Add(int x, int y)
36 {
37 Console.WriteLine("Add() invoked on thread {0}",
38 Thread.CurrentThread.ManagedThreadId);
39 Thread.Sleep(5000);
40 return x + y;
41 }
42 }
43 }
在这个示例中我们可以自定义一些数据然后AddComplete方法来访问它,itfAR.AsyncState就包含了自定义数据。


浙公网安备 33010602011771号