C#中的委托和事件学习(续)
需要注意代码输出中的几个变化: 1.我们需要在客户端程序中调用Console.ReadKey()方法来暂停客户端,以提供足够的时间来让异步方法去执行完代码,不然的话客户端的程序到此处便会运行结束,程序会退出,不会看到任何订阅者方法的输出,因为它们根本没来得及执行完毕。原因是这样的:客户端所在的线程我们通常称为主线程,而执行订阅者方法的线程来自线程池,属于后台线程(Background Thread),当主线程结束时,不论后台线程有没有结束,都会退出程序。(当然还有一种前台线程(Foreground Thread),主线程结束后必须等前台线程也结束后程序才会退出,关于线程的讨论可以开辟另一个庞大的主题,这里就不讨论了)。 委托和方法的异步调用 通常情况下,如果需要异步执行一个耗时的操作,我们会新起一个线程,然后让这个线程去执行代码。但是对于每一个异步调用都通过创建线程来进行操作显然会对性能产生一定的影响,同时操作也相对繁琐一些。.Net中可以通过委托进行方法的异步调用,就是说客户端在异步调用方法时,本身并不会因为方法的调用而中断,而是从线程池中抓取一个线程去执行该方法,自身线程(主线程)在完成抓取线程这一过程之后,继续执行下面的代码,这样就实现了代码的并行执行。使用线程池的好处就是避免了频繁进行异步调用时创建、销毁线程的开销。 如同上面所示,当我们在委托对象上调用BeginInvoke()时,便进行了一个异步的方法调用。上面的例子中是在事件的发布和订阅这一过程中使用了异步调用,而在事件发布者和订阅者之间往往是松耦合的,发布者通常不需要获得订阅者方法执行的情况;而当使用异步调用时,更多情况下是为了提升系统的性能,而并非专用于事件的发布和订阅这一编程模型。而在这种情况下使用异步编程时,就需要进行更多的控制,比如当异步执行方法的方法结束时通知客户端、返回异步执行方法的返回值等。本节就对BeginInvoke()方法、EndInvoke()方法和其相关的IAysncResult做一个简单的介绍。 NOTE:注意此处我已经不再使用发布者、订阅者这些术语,因为我们不再是讨论上面的事件模型,而是讨论在客户端程序中异步地调用方法,这里有一个思维的转变。 我们看这样一段代码,它演示了不使用异步调用的通常情况: class Program7 { static void Main(string[] args) { Console.WriteLine("Client application started!n"); Thread.CurrentThread.Name = "Main Thread"; Calculator cal = new Calculator(); int result = cal.Add(2, 5); Console.WriteLine("Result: {0}n", result); // 做某些其它的事情,模拟需要执行3秒钟 for (int i = 1; i <= 3; i++) { Thread.Sleep(TimeSpan.FromSeconds(i)); Console.WriteLine("{0}: Client executed {1} second(s).", Thread.CurrentThread.Name, i); } Console.WriteLine("nPress any key to exit..."); Console.ReadKey(); } } public class Calculator { public int Add(int x, int y) { if (Thread.CurrentThread.IsThreadPoolThread) { Thread.CurrentThread.Name = "Pool Thread"; } Console.WriteLine("Method invoked!"); // 执行某些事情,模拟需要执行2秒钟 for (int i = 1; i <= 2; i++) { Thread.Sleep(TimeSpan.FromSeconds(i)); Console.WriteLine("{0}: Add executed {1} second(s).", Thread.CurrentThread.Name, i); } Console.WriteLine("Method complete!"); return x + y; } } 上面代码有几个关于对于线程的操作,如果不了解可以看一下下面的说明,如果你已经了解可以直接跳过: •Thread.Sleep(),它会让执行当前代码的线程暂停一段时间(如果你对线程的概念比较陌生,可以理解为使程序的执行暂停一段时间),以毫秒为单位,比如Thread.Sleep(1000),将会使线程暂停1秒钟。在上面我使用了它的重载方法,个人觉得使用TimeSpan.FromSeconds(1),可读性更好一些。 (编辑:焦作站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |