C#多线程之异步编程
c#中异步编程,主要有两种方法: 1、委托的异步调用; 2、Task的await,async (c# 4.5)
我们来看例子:
/// <summary>
/// 异步保存网页,url:网页地址,path:要保存的位置
/// </summary>
private void SavePageAsync(string url, string path)
{
Func<string, string, bool> fun = SavePageSingleFile;
IAsyncResult result = fun.BeginInvoke(url, path, new AsyncCallback(SavePageCompleted), null);
}
Func,是系统定义好的委托类型,当然也可以自定义委托了,委托的本质是一个类,它有一个BeginInvoke 异步调用方法。SavePageSingleFile方法是委托要执行的方法:
private bool SavePageSingleFile(string url, string path)
{
bool result = false;
try
{
CDO.Message message = new CDO.MessageClass();
ADODB.Stream stream = null;
message.MimeFormatted = true;
message.CreateMHTMLBody(url, CDO.CdoMHTMLFlags.cdoSuppressNone, "", "");
stream = message.GetStream();
stream.SaveToFile(path, ADODB.SaveOptionsEnum.adSaveCreateOverWrite);
message = null;
stream.Close(); result = true;
}
catch (Exception ex)
{
Logger.Debug("保存文件出错:" + ex.Message);
}
return result;
}
委托任务完成后的回调方法 SavePageCompleted:
private void SavePageCompleted(IAsyncResult result)
{
try
{
var handler = (Func<string, string, bool>)((AsyncResult)result).AsyncDelegate;
var r = handler.EndInvoke(result); this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
this.Opacity = ; if (CloseWaittingWindow != null)
{
CloseWaittingWindow();
}
this.Cursor = System.Windows.Input.Cursors.Hand; MessageTip tip = new MessageTip();
if (r)
{
tip.Show("保存网页", "文件保存成功");
}
else
{
tip.Show("保存网页", "文件保存失败");
}
}
);
}
catch (Exception ex)
{
Logger.Debug("保存页面文件出错:" + ex.Message);
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
new MessageTip().Show("保存网页", "文件保存出错");
this.Opacity = ; if (CloseWaittingWindow != null)
{
CloseWaittingWindow();
}
this.Cursor = System.Windows.Input.Cursors.Hand;
}
);
}
}
最后看下 SavePageAsync 方法的调用:
/// <summary>
/// 保存当前页面
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSavePage_Click(object sender, RoutedEventArgs e)
{
if (this.DBVisitViewModel.CanSavePageExcute)
{
string url = this.WebPageBrower.Url.AbsoluteUri;
if (!Tool.CheckUrl(url))
{
new MessageTip().Show("保存页面", "当前页面无法保存");
return;
} SaveFileDialog sfd = new SaveFileDialog(); sfd.InitialDirectory = @"D:\";
sfd.Filter = "mht file|*.mht"; if (sfd.ShowDialog() == DialogResult.OK)
{
if (OpenWaittingWindow != null)
{
this.Cursor = System.Windows.Input.Cursors.Wait;
SavePageAsync(url, sfd.FileName); this.Opacity = 0.8;
OpenWaittingWindow("正在保存网页,请稍等...");
}
}
}
}
在framework 4.0的时候,委托异步调用显得很方便,到了4.5的时候,我们可以用Task实现异步调用。改下上面的例子:
private async void SavePageAsync(string url, string path)
{
var r = await SavePageSingleFile(url, path); try
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
this.Opacity = ; if (CloseWaittingWindow != null)
{
CloseWaittingWindow();
}
this.Cursor = System.Windows.Input.Cursors.Hand; MessageTip tip = new MessageTip();
if (r)
{
tip.Show("保存网页", "文件保存成功");
}
else
{
tip.Show("保存网页", "文件保存失败");
}
}
);
}
catch (Exception ex)
{
Logger.Debug("保存页面文件出错:" + ex.Message);
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
new MessageTip().Show("保存网页", "文件保存出错");
this.Opacity = ; if (CloseWaittingWindow != null)
{
CloseWaittingWindow();
}
this.Cursor = System.Windows.Input.Cursors.Hand;
}
);
} }
static async Task<bool> SavePageSingleFile(string url, string path)
{
return await Task.Run(() =>
{
bool result = false;
try
{
CDO.Message message = new CDO.MessageClass();
ADODB.Stream stream = null;
message.MimeFormatted = true;
message.CreateMHTMLBody(url, CDO.CdoMHTMLFlags.cdoSuppressNone, "", "");
stream = message.GetStream();
stream.SaveToFile(path, ADODB.SaveOptionsEnum.adSaveCreateOverWrite);
message = null;
stream.Close(); result = true;
}
catch (Exception ex)
{
Logger.Debug("保存文件出错:" + ex.Message);
}
return result;
});
}
第5行后的try,catch语句块,就是保存网页后的回调,它的执行是在子线程中,因此,在wpf 中要用 Dispatcher(回调中牵扯到对页面的操作)。为了简化这一例子,我这儿给出一个简单的可以执行的例子:
static void Main(string[] args)
{
Add(,);
Console.WriteLine("主线程:" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("main Thread go on sth");
Console.Read();
} private async static void Add(int x, int y)
{
Console.WriteLine("主线程:" + Thread.CurrentThread.ManagedThreadId);
var t = await TestAsync(x,y);
Console.WriteLine("正在等待完成任务,当前线程:"+Thread.CurrentThread.ManagedThreadId); Console.WriteLine("运行结果:" + t);
}
static async Task<int> TestAsync(int x, int y)
{
return await Task.Run(() =>
{
Thread.Sleep();
Console.WriteLine("子线程:" + Thread.CurrentThread.ManagedThreadId);
return x + y;
});
}
运行结果:

异步编程主要是为了解决耗时的任务占用主线程的问题,比如ajax的异步调用,不会导致页面卡死。好了,今天就谈到这里,该吃中午饭了。
C#多线程之异步编程的更多相关文章
- 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
[源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...
- 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress
[源码下载] 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithPro ...
- 初步谈谈 C# 多线程、异步编程与并发服务器
多线程与异步编程可以达到避免调用线程异步阻塞作用,但是两者还是有点不同. 多线程与异步编程的异同: 1.线程是cpu 调度资源和分配的基本单位,本质上是进程中的一段并发执行的代码. 2.线程编程的思维 ...
- C++多线程并发---异步编程
线程同步主要是为了解决对共享数据的竞争访问问题,所以线程同步主要是对共享数据的访问同步化(按照既定的先后次序,一个访问需要阻塞等待前一个访问完成后才能开始).这篇文章谈到的异步编程主要是针对任务或线程 ...
- C# - 多线程 之 异步编程
异步编程 同步编程,请求响应模型,同步化.顺序化.事务化. 异步编程,事件驱动模型,以 Fire and Forget 方式实现. 异步编程模式 -§- 异步编程模型 (APM) 模式: IAsyn ...
- 多线程之异步编程: 经典和最新的异步编程模型,async与await
经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...
- 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...
- c# 中的多线程和异步
前言: 1.异步和多线程有区别吗? 答案:多线程可以说是实现异步的一种方法方法,两者的共同目的:使主线程保持对用户操作的实时响应,如点击.拖拽.输入字符等.使主程序看起来实时都保持着等待用户响应的状态 ...
- Async await 异步编程说明
希望在编程上有些许提高所以 最近连续2篇博客都在说明多线程和异步编程的使用,异步和多线程之间区别请自行百度,因为理解不是特别透彻就不在叙述以免误导大家,这里写下新研究整理 task 和 await ...
随机推荐
- PyCharm安装Pygame方法
最近在自学Python,然后终于到了项目实战的时候了,而且还是做一个游戏,热情直接被调动起来了,嘿嘿 首先要安装一个Pygame 环境 win7 先去 这里 下载对应Python的Pygame版本 如 ...
- JVM自动内存管理-Java内存区域与内存溢出异常
摘要: JVM内存的划分,导致内存溢出异常的可能区域. 1. JVM运行时内存区域 JVM在执行Java程序的过程中会把它所管理的内存划分为以下几个区域: 1.1 程序计数器 程序计数器是一块较小的内 ...
- 拥抱.NET Core系列:MemoryCache 缓存过期
在上一篇"拥抱.NET Core系列:MemoryCache 初识"中我们基本了解了缓存的添加.删除.获取,那么今天我们来看看缓存的过期机制.这里和上篇一样将把"Micr ...
- Java多维数组各轴长度可以不对齐
- uva1625
思路:每次选择颜色面临有两个选择:1.序列A的首部颜色 2.序列B的首部元素,定义状态d[i][j]表示A序列已经选取了前i个颜色,B序列已经选取了前j个颜色的情况下最小的L(c)总和. 状态转移:c ...
- POJ - 1321 dfs [kuangbin带你飞]专题一
枚举行和列即可,当前已经放下cnt个棋子,当前已经搜索到第r行,如果 n - r + cnt < k 直接退出,因为后面无法放下剩下的棋子. AC代码 #include<cstdio&g ...
- Fabric单节点安装备忘
安装文档:http://www.cnblogs.com/studyzy/p/7437157.html 安装上面的文档安装成功,但是过程中遇到一些问题. 一.go的源码包可能下载不下来,因为被墙,go官 ...
- Ambari安装小记
在Ambari配置过程中,组件的定制与分配很重要
- JavaScript中基本数据类型和引用数据类型的区别
1.基本数据类型和引用数据类型 ECMAScript包括两个不同类型的值:基本数据类型和引用数据类型. 基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构成的对象. 当我们把变量赋值给一个变 ...
- MyBatis入门一
本人只是刚刚学习MyBatis,作为学习路程的记录,写的不好,不完善的地方请多多包涵: 首先,先比较一下Hibernate和MyBatis两种框架之间的区别: 两种都是ORM框架,但是Hibernat ...