在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
APM是.NET中异步编程模型的缩写(Asynchronous Programing Model)。 通过异步编程,使得我们的程序可以更加高效的利用系统资源。 主要内容:
1. 一个APM的例子.Net中的异步模型非常完善,只要看到Begin***者End***方法。基本都是相对***方法的异步调用方式。 (注:***是方法的名称) 所以在.Net中实现一个异步调用是很方便的,下面用个小例子来演示一个异步操作。 首先是同步的方式请求百度搜索10次。(分别搜索1,2,3。。。。10) public class CLRviaCSharp_21 { static void Main(string[] args) { // 用百度分别检索1,2,3。。。9,共检索10次 DateTime start = DateTime.Now; string strReq = "http://www.baidu.com/s?wd={0}"; for (int i = 0; i < 10; i++) { var req = WebRequest.Create(string.Format(strReq, i)); // 注意这里的GetResponse是同步方法 var res = req.GetResponse(); Console.WriteLine("检索 {0} 的结果已经返回!", i); res.Close(); } Console.WriteLine("耗用时间:{0}毫秒", TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks).TotalMilliseconds); Console.ReadKey(true); } } 结果如下:总共消耗时间33秒多。
异步的方式如下: public class CLRviaCSharp_21 { static DateTime start; static void Main(string[] args) { // 用百度分别检索1,2,3。。。9,共检索10次 start = DateTime.Now; string strReq = "http://www.baidu.com/s?wd={0}"; for (int i = 0; i < 10; i++) { var req = WebRequest.Create(string.Format(strReq, i)); // 注意这里的BeginGetResponse就是异步方法 var res = req.BeginGetResponse(ProcessWebResponse, req); } Console.ReadKey(true); } private static void ProcessWebResponse(IAsyncResult result) { var req = (WebRequest)result.AsyncState; string strReq = req.RequestUri.AbsoluteUri; using (var res = req.EndGetResponse(result)) { Console.Write("检索 {0} 的结果已经返回!\t", strReq.Substring(strReq.Length - 1)); Console.WriteLine("耗用时间:{0}毫秒", TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks).TotalMilliseconds); } } } 结果如下:总共消耗的时间应该是下面所有时间中最长的那个,即9.5秒左右。
2. GUI中的APM异步编程除了在服务端会大量应用,在有GUI的客户端也应用比较多(为了保证客户端的界面不会假死)。 但是Winform或WPF程序中,改变界面元素状态只有通过UI线程,其他线程如果试图改变UI元素,就会抛出异常(System.InvalidOperationException)。 using System; using System.Windows.Forms; using System.Net; public class CLRviaCSharp_21 { static void Main(string[] args) { MyWindowsForm mf = new MyWindowsForm(); mf.ShowDialog(); } } internal class MyWindowsForm : Form { public MyWindowsForm() { Text = "Click in the window to start a web request"; Width = 800; Height = 600; } protected override void OnMouseClick(MouseEventArgs e) { // 开始异步web请求 Text = "web request initilized"; var webreq = WebRequest.Create("http://www.baidu.com"); webreq.BeginGetResponse(ProcessWebResponse, webreq); base.OnMouseClick(e); } private void ProcessWebResponse(IAsyncResult result) { var req = (WebRequest)result.AsyncState; using (var res = req.EndGetResponse(result)) { // SynchronizationContext.Current.Post(updateUI, res); // 这里改变UI元素Form的Text属性,抛出了异常 Text = "Content length: " + res.ContentLength; } } } 那么其他线程如何改变UI元素呢。为了保证UI始终有响应,必须能够让其他线程也能改变UI元素。 答案就在上面代码中抛异常的上面一句代码。利用SynchronizationContext的Current属性来获取UI线程的同步上下文信息。 然后调用其Post方法,异步的更新UI元素。 using System; using System.Windows.Forms; using System.Net; using System.Threading; public class CLRviaCSharp_21 { static void Main(string[] args) { MyWindowsForm mf = new MyWindowsForm(); mf.ShowDialog(); } } internal class MyWindowsForm : Form { public MyWindowsForm() { Text = "Click in the window to start a web request"; Width = 800; Height = 600; } protected override void OnMouseClick(MouseEventArgs e) { // 开始异步web请求 Text = "web request initilized"; var webreq = WebRequest.Create("http://www.baidu.com"); webreq.BeginGetResponse(ProcessWebResponse, webreq); base.OnMouseClick(e); } private void ProcessWebResponse(IAsyncResult result) { var req = (WebRequest)result.AsyncState; using (var res = req.EndGetResponse(result)) { SynchronizationContext.Current.Post(updateUI, res); } } private void updateUI(object state) { var res = (WebResponse)state; // 这里改变UI元素Form的Text属性, updateUI这个函数是由UI线程执行的 Text = "Content length: " + res.ContentLength; } } 这样的实现看着很繁琐,所以《CLR via C#》作者Jeffrey实现了一个小方法(SyncContextCallback)来简化这个步骤。 using System; using System.Windows.Forms; using System.Net; using System.Threading; public class CLRviaCSharp_21 { static void Main(string[] args) { MyWindowsForm mf = new MyWindowsForm(); mf.ShowDialog(); } } internal class MyWindowsForm : Form { public MyWindowsForm() { Text = "Click in the window to start a web request"; Width = 800; Height = 600; } protected override void OnMouseClick(MouseEventArgs e) { // 开始异步web请求 Text = "web request initilized"; var webreq = WebRequest.Create("http://www.baidu.com"); webreq.BeginGetResponse(SyncContextCallback(ProcessWebResponse), webreq); base.OnMouseClick(e); } private void ProcessWebResponse(IAsyncResult result) { var req = (WebRequest)result.AsyncState; using (var res = req.EndGetResponse(result)) { // 这里改变UI元素Form的Text属性, // 这次是在UI线程执行的,SyncContextCallback中获取了UI线程的同步上下文, // 然后用Post方法调用了ProcessWebResponse函数 Text = "Content length: " + res.ContentLength; } } // 大牛Jeffrey实现的SyncContextCallback方法 private static AsyncCallback SyncContextCallback(AsyncCallback callback) { SynchronizationContext sc = SynchronizationContext.Current; // 如果没有同步上下文,直接返回传入的东西 if (sc == null) return callback; // 返回一个委托,这个委托将委托Post到捕捉到的SC中 return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult); } }
3. APM的优劣点上面两个例子,可以看出APM的一些优势,第一个例子说明异步的效率高。第二个GUI的例子说明异步可以增强用户体验。 其实APM的优势总结起来有以下几点:
当然,任何技术都不是完美的,有其适用的一面,也有其不适用的一面。 了解它的缺点,有时候甚至可以帮助我们更好的使用它。 APM的劣势主要有以下几点:
4. AMP使用中的注意事项使用APM时以下几点需要注意:
|
请发表评论