C#多线程之异步编程

c#中异步编程,主要有两种方法: 1、委托的异步调用; 2、Task的await,async (c# 4.5)

我们来看例子:

1         /// <summary>
2         /// 异步保存网页,url:网页地址,path:要保存的位置
3         /// </summary>
4         private void SavePageAsync(string url, string path)
5         {
6             Func<string, string, bool> fun = SavePageSingleFile;
7             IAsyncResult result = fun.BeginInvoke(url, path, new AsyncCallback(SavePageCompleted), null);
8         }

Func,是系统定义好的委托类型,当然也可以自定义委托了,委托的本质是一个类,它有一个BeginInvoke 异步调用方法。SavePageSingleFile方法是委托要执行的方法:

 1         private bool SavePageSingleFile(string url, string path)
 2         {
 3             bool result = false;
 4             try
 5             {
 6                 CDO.Message message = new CDO.MessageClass();
 7                 ADODB.Stream stream = null;
 8                 message.MimeFormatted = true;
 9                 message.CreateMHTMLBody(url, CDO.CdoMHTMLFlags.cdoSuppressNone, "", "");
10                 stream = message.GetStream();
11                 stream.SaveToFile(path, ADODB.SaveOptionsEnum.adSaveCreateOverWrite);
12                 message = null;
13                 stream.Close();
14
15                 result = true;
16             }
17             catch (Exception ex)
18             {
19                 Logger.Debug("保存文件出错:" + ex.Message);
20             }
21             return result;
22         }
  委托任务完成后的回调方法 SavePageCompleted:
 1       private void SavePageCompleted(IAsyncResult result)
 2        {
 3             try
 4             {
 5                 var handler = (Func<string, string, bool>)((AsyncResult)result).AsyncDelegate;
 6                 var r = handler.EndInvoke(result);
 7
 8                 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
 9                                    (ThreadStart)delegate()
10                                    {
11                                        this.Opacity = 1;
12
13                                        if (CloseWaittingWindow != null)
14                                        {
15                                            CloseWaittingWindow();
16                                        }
17                                        this.Cursor = System.Windows.Input.Cursors.Hand;
18
19                                        MessageTip tip = new MessageTip();
20                                        if (r)
21                                        {
22                                            tip.Show("保存网页", "文件保存成功");
23                                        }
24                                        else
25                                        {
26                                            tip.Show("保存网页", "文件保存失败");
27                                        }
28                                    }
29                           );
30             }
31             catch (Exception ex)
32             {
33                 Logger.Debug("保存页面文件出错:" + ex.Message);
34                 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
35                                  (ThreadStart)delegate()
36                                  {
37                                      new MessageTip().Show("保存网页", "文件保存出错");
38                                      this.Opacity = 1;
39
40                                      if (CloseWaittingWindow != null)
41                                      {
42                                          CloseWaittingWindow();
43                                      }
44                                      this.Cursor = System.Windows.Input.Cursors.Hand;
45                                  }
46                         );
47             }
48         }

最后看下 SavePageAsync 方法的调用:

 1         /// <summary>
 2         /// 保存当前页面
 3         /// </summary>
 4         /// <param name="sender"></param>
 5         /// <param name="e"></param>
 6         private void btnSavePage_Click(object sender, RoutedEventArgs e)
 7         {
 8             if (this.DBVisitViewModel.CanSavePageExcute)
 9             {
10                 string url = this.WebPageBrower.Url.AbsoluteUri;
11                 if (!Tool.CheckUrl(url))
12                 {
13                     new MessageTip().Show("保存页面", "当前页面无法保存");
14                     return;
15                 }
16
17                 SaveFileDialog sfd = new SaveFileDialog();
18
19                 sfd.InitialDirectory = @"D:\";
20                 sfd.Filter = "mht file|*.mht";
21
22                 if (sfd.ShowDialog() == DialogResult.OK)
23                 {
24                     if (OpenWaittingWindow != null)
25                     {
26                         this.Cursor = System.Windows.Input.Cursors.Wait;
27                         SavePageAsync(url, sfd.FileName);
28
29                         this.Opacity = 0.8;
30                         OpenWaittingWindow("正在保存网页,请稍等...");
31                     }
32                 }
33             }
34         }

在framework 4.0的时候,委托异步调用显得很方便,到了4.5的时候,我们可以用Task实现异步调用。改下上面的例子:

 1        private async void SavePageAsync(string url, string path)
 2         {
 3             var r = await SavePageSingleFile(url, path);
 4
 5             try
 6             {
 7                 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
 8                                    (ThreadStart)delegate()
 9                                    {
10                                        this.Opacity = 1;
11
12                                        if (CloseWaittingWindow != null)
13                                        {
14                                            CloseWaittingWindow();
15                                        }
16                                        this.Cursor = System.Windows.Input.Cursors.Hand;
17
18                                        MessageTip tip = new MessageTip();
19                                        if (r)
20                                        {
21                                            tip.Show("保存网页", "文件保存成功");
22                                        }
23                                        else
24                                        {
25                                            tip.Show("保存网页", "文件保存失败");
26                                        }
27                                    }
28                           );
29             }
30             catch (Exception ex)
31             {
32                 Logger.Debug("保存页面文件出错:" + ex.Message);
33                 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
34                                  (ThreadStart)delegate()
35                                  {
36                                      new MessageTip().Show("保存网页", "文件保存出错");
37                                      this.Opacity = 1;
38
39                                      if (CloseWaittingWindow != null)
40                                      {
41                                          CloseWaittingWindow();
42                                      }
43                                      this.Cursor = System.Windows.Input.Cursors.Hand;
44                                  }
45                         );
46             }
47
48
49
50         }
51         static async Task<bool> SavePageSingleFile(string url, string path)
52         {
53             return await Task.Run(() =>
54             {
55                 bool result = false;
56                 try
57                 {
58                     CDO.Message message = new CDO.MessageClass();
59                     ADODB.Stream stream = null;
60                     message.MimeFormatted = true;
61                     message.CreateMHTMLBody(url, CDO.CdoMHTMLFlags.cdoSuppressNone, "", "");
62                     stream = message.GetStream();
63                     stream.SaveToFile(path, ADODB.SaveOptionsEnum.adSaveCreateOverWrite);
64                     message = null;
65                     stream.Close();
66
67                     result = true;
68                 }
69                 catch (Exception ex)
70                 {
71                     Logger.Debug("保存文件出错:" + ex.Message);
72                 }
73                 return result;
74             });
75         }

第5行后的try,catch语句块,就是保存网页后的回调,它的执行是在子线程中,因此,在wpf 中要用 Dispatcher(回调中牵扯到对页面的操作)。为了简化这一例子,我这儿给出一个简单的可以执行的例子:

 1   static void Main(string[] args)
 2         {
 3             Add(2,3);
 4             Console.WriteLine("主线程:" + Thread.CurrentThread.ManagedThreadId);
 5             Console.WriteLine("main Thread go on sth");
 6             Console.Read();
 7         }
 8
 9         private async static void Add(int x, int y)
10         {
11             Console.WriteLine("主线程:" + Thread.CurrentThread.ManagedThreadId);
12             var t = await TestAsync(x,y);
13             Console.WriteLine("正在等待完成任务,当前线程:"+Thread.CurrentThread.ManagedThreadId);
14
15             Console.WriteLine("运行结果:" + t);
16         }
17         static async Task<int> TestAsync(int x, int y)
18         {
19             return await Task.Run(() =>
20             {
21                 Thread.Sleep(1000);
22                 Console.WriteLine("子线程:" + Thread.CurrentThread.ManagedThreadId);
23                 return x + y;
24             });
25         }

运行结果:

异步编程主要是为了解决耗时的任务占用主线程的问题,比如ajax的异步调用,不会导致页面卡死。好了,今天就谈到这里,该吃中午饭了。

时间: 2024-10-08 01:30:30

C#多线程之异步编程的相关文章

初步谈谈 C# 多线程、异步编程与并发服务器

多线程与异步编程可以达到避免调用线程异步阻塞作用,但是两者还是有点不同. 多线程与异步编程的异同: 1.线程是cpu 调度资源和分配的基本单位,本质上是进程中的一段并发执行的代码. 2.线程编程的思维符合正常人的思维习惯,线程中的处理程序依然是顺序执行,所以编程起来比较方便,但是缺点也是明显的,多线程的使用会造成多线程之间的上下文切换带来系统花销,并且共享变量之间也是会造成死锁的问题. 3.因为异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变

多线程和异步编程示例和实践-踩过的坑

上两篇文章,主要介绍了Thread.ThreadPool和TPL 多线程异步编程示例和实践-Thread和ThreadPool 多线程异步编程示例和实践-Task 本文中,分享两则我们在做多线程和异步编程中实际踩过的坑,实际生产环境遇到的问题,以及解决办法. 1. HttpClient 业务场景:使用HttpClient实现第三方业务推送,当第三方的Http服务器不通.或者返回很慢时 线程数暴涨 Asp.Net\Asp.Net MVC场景下,并发多线程导致的线程阻塞:HttpClient.Pos

C# - 多线程之 异步编程

异步编程 同步编程,请求响应模型,同步化.顺序化.事务化. 异步编程,事件驱动模型,以 Fire and Forget 方式实现. 异步编程模式 ?-§-?异步编程模型 (APM) 模式: IAsyncResult 模式,异步操作需要 Begin 和 End 方法: ?-§-?基于事件的异步模式(EAP):事件.事件处理程序委托类型和 EventArg 派生类型: ?-§-?基于任务的异步模式(TAP):推荐模式,.NET Framework 4 引入,基于 System.Threading.T

多线程之异步编程: 经典和最新的异步编程模型,async与await

经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经典的异步编程模型(IAsyncResult)实现一个支持异步操作的类Thread/Async/ClassicAsync.cs /* * 使用经典的异步编程模型(IAsyncResult)实现一个支持异步操作的类 */ using System; using System.Collections.Ge

C#多线程与异步

多线程与异步编程,一直是小白变成(●—●)的一个坎.平时也用到过不少多线程与异步操作,在这里进行一下记录. 异步与多线程的概念 平时可能会遇见需要爬网页数据,这个时候如果数据很庞大.那么单线程会造成等待.如果这个时候使用Thread开一个线程,经管会避免UI线程卡顿,但是依然会很慢.这就是典型的多线程错误使用情况. 那么针对此情景,需要进行如何处理呢?首先要理解一下,网页数据的操作,IO操作. IO操作:IO流实际上是一种无结构的字节序或字符序列,进行插入和移除就是IO操作.均是以IO流为基础,

Async await 异步编程说明

希望在编程上有些许提高所以 最近连续2篇博客都在说明多线程和异步编程的使用,异步和多线程之间区别请自行百度,因为理解不是特别透彻就不在叙述以免误导大家,这里写下新研究整理 task  和 await 的异步编程使用 调用子方法和耗时方法如下 /// <summary> /// 有返回值异步方法 /// </summary> /// <returns></returns> static async Task<int> HaveReturnAsync

C#的多线程——使用async和await来完成异步编程(Asynchronous Programming with async and await)

https://msdn.microsoft.com/zh-cn/library/mt674882.aspx 侵删 更新于:2015年6月20日 欲获得最新的Visual Studio 2017 RC文档,参考Visual Studio 2017 RC Documentation. 使用异步编程,你可以避免性能瓶颈和提升总体相应效率.然而,传统的异步方法代码的编写方式比较复杂,导致它很难编写,调试和维护. Visual Studio 2012引入了一个简单的异步编程的方法,依赖.NET Fram

多线程异步编程示例和实践-Thread和ThreadPool

说到多线程异步编程,总会说起Thread.ThreadPool.Task.TPL这一系列的技术.总结整理了一版编程示例和实践,分享给大家. 先从Thread和ThreadPool说起: 1. 创建并启动线程 2. 暂停线程 当前线程在执行Thread.Sleep方法时,会等待指定的时间(1000ms)此时,当前线程处于阻塞状态:WaitSleepJoin 3. 线程等待 当程序运行时,启动了一个耗时较长的线程打印数字,每次打印输出前需要等待1000ms,我们在主程序中调用ThreadJoin方法

C#——await与async实现多线程异步编程

曾经,我们也许用过Thread.在主线程运行的时候.新开还有一个新线程,来运行新方法. 今天看别人发给我的一段代码的时候发现了一个不认识的await,可是又感觉非常熟悉的样子,感觉是线程那块儿的东西,查了下,发现一个简单的方法实现多线程异步编程. (PS:framework 在4.5以上才干够哦~) /// <summary> /// 測试方法 /// </summary> /// <remarks>创建者:刘慧超; 创建时间:2015-08-24 20:22:14&l