http://www.cnblogs.com/fangyz/p/5134018.html

从.NET4.5开始,用async和await关键字再加上Task.Run是一个非常不错的异步编程模型。

1.await和async

  异步模式从技术上看就是利用委托来实现的,它 的主要好处是在异步执行的过程中,用户仍然可以操控UI界面。使用Task类和使用Thread类有很多相似的地方,Task类也是通过调用方法去实现一 个任务的完成,方法可是是命名方法或匿名方法,在执行过程中可使用async和await来实现异步执行。async是一个修饰符,它只能用在方法或者事 件处理程序的签名中。对于方法可分为有返回值和无返回值两种情况,事件则只有一种,如下面三条语句所示:

    private async Task<int> MethodAsync();//有返回值的异步方法

    private async Task MethodAsync();//无返回值的异步方法

    private async void btnOk_Click();//异步事件处理程序

  await是一个运算符,它表示等待异步执行 的结果。也可以理解为await运算符实际上是对方法的返回值进行操作,也就是对Task<Result>进行操作,而不是对方法本身进行操 作。还有一点要注意,await是一定要放在异步方法的内部,如果没有放在内部的话,VS会自动报错。以下是async和await使用的例子: 

    private async void button5_Click(object sender, EventArgs e)
    {
      Task a = Method1Async();
      //此处可继续执行其他代码
      await a;//等待任务a完成
      Task<int> b = Method2Async();
      //此处可继续执行其他代码
      int c = await b;//等待任务b完成,且可以拿到任务b的返回值
    }

    Task Method1Async();
    async Task<int> Method2Async()
    {
      await Task.Delay(100);
      return 1;
    }

  await和同步编程最大的不同之处是:异步等待任务完成的时候,在不会继续执行后面的代码时,也不会影响界面的操作。在.NET提供的类中,异步方法都是约定用Async作为后缀,这样可以很清楚的知道这个方法是异步方法还是同步方法。

2. 创建任务

  创建任务也就是将任务与要执行的方法联系起
来,编写任务执行的方法时,这个方法既可以是同步方法也可以是异步方法,还可以是匿名方法。执行异步方法时,必须用async和Task共同表示没有返回
值的任务,用async和Task<TResult>共同表示返回值为TResult的任务。以下是定义执行任务的方法。

    private async void button5_Click(object sender, EventArgs e)
    {

      //Task.Run方法表示使用默认的任务调度程序在线程池中通过后台执行指定的任务

      //如果不需要自己去调度方法,使用这个方式最方便
      await Task.Run(()=>Method1Async());//执行同步方法
      int c = await Task.Run(()=>Method2Async());//执行异步方法
      await Task.Run(async () => { c = 2; });//执行异步匿名方法
    }
    void Method1Async();
    async Task<int> Method2Async(){...}

  Task.Run方法常用的重载形式有以下4种,另外它也是可以用new关键字显示创建任务,但是这种方式用的不多。

    Task Run(Func<Task> function);//执行不带返回值的任务

    Task<TResult> Run<TResult>(Func<Task<TResult>> function);//执行带返回值的任务

    
Task<TResult> Run<TResult>(Func<Task<TResult>>
function, CancellationToken cancellationToken);//执行过程中可以监听取消通知

    Task Run(Func<Task> function, CancellationToken cancellationToken);//执行过程中可以监听取消通知

3. 终止任务

  在执行任务时肯定会出现需要终止任务的情况,
这里的终止告诉任务你要尽快停下来不再执行了,而不是直接销毁任务实例。这里可以打个比方,学生一起出去吃饭了,学生与老师都在班群里面,突然班群里老师
说要让同学们集合,如果所有同学都看到这个消息,然后学生们开始出发,这样就可以正确的集合。上面的例子有一个很重要的前提,那就是所有同学都要看到这个
消息,也就是学生是时刻监听消息的。CancellationTokenSource类和CancellationToken结构用于实现多线程、线程池
和Task任务的取消操作,处理模式与上面的例子相似。创建的班群就是CancellationTokenSource对象,收到的通知就是
CancellationToken对象。CancellationTokenSource用于创建取消通知,CancellationToken则用于
传播应取消操作的通知,当调用任务前,可以先创建取消源对象CancellationTokenSource
cts=new CancellationTokenSource();,如果希望在30秒后自动发出取消通知,可以传入参数
CancellationTokenSource(TimeSpan.FromSeconds(30));CancellationToken
ct=cts.Token;,后一句代码是拿到取消的通知。CancellationTokenSource还有一个Cancel方法,将这个属性设为
true时,该方法会将所有添加了取消标记的CancellationToken对象的IsCancellationRequested属性都设置为
true,这样取消通知就传递到了正在执行的任务。

  任务收到取消通知后,可以选择两种方式来终止
操作。第一种方式是简单的从委托返回。这种实现方式类似于在调用任务的代码中一个bool值来表示取消通知,任务收到后就直接返回了。当采用这种方式时任
务状态的返回值为TaskStatus.RanToCompletion枚举值,它表示正常完成,而不是TaskStatus.Canceled枚举值。
第二种方式是在代码里引发OperationCanceledException异常,并将其传递到在其上请求了取消的标记,采用这种方式取消的任务会转
换为用Canceled枚举值表示的状态。完成引发异常的首选方式是调用ct.ThrowIfCancellationRequestes();。以下是
代码示例,写了一个winform程序,利用进度条来取消任务。第一个图是没有引发异常时,程序退出for循环,执行后面的代码后返回了,第二张图是第二
种方式,引发了异常后直接跳转到catch语句块了。

     CancellationTokenSource cts;
private async void button3_Click(object sender, EventArgs e)
{
progressBar1.Maximum = 100;
progressBar1.Value = 0;
cts = new CancellationTokenSource();
var aa = MYThreadAsync("a", cts.Token);
try
{
await aa;
listBox1.Items.Add("await后面");
}
catch
{
if (aa.IsCanceled)
listBox1.Items.Add("a取消");
}
} private void button4_Click(object sender, EventArgs e)
{
cts.Cancel();
} public async Task MYThreadAsync(string s, CancellationToken ct)
{
for (int i = 0; i < 50; i++)
{
if (ct.IsCancellationRequested)
break; //点击关闭按钮,IsCancellationRequested就为true,就会退出for循环,这是第一种方式
progressBar1.Value += 2;
await Task.Delay(100);
ct.ThrowIfCancellationRequested();//这是第二种方式,它会终止任务并且返回catch语句块里面
}
listBox1.Items.Add("任务" + s + "完成了");
}

4. 获取任务执行的状态

  在异步编程中,很显然任务执行的状态是一个非 常重要的参数。在任务的生命周期里,可以通过Status属性来获取任务执行的状态,当任务完成后还可以通过任务属性知道任务完成的情况。可利用任务实例 的Status属性获取任务执行的状态,任务执行的状态用TaskStatus枚举表示,以下是TaskStatus的枚举值:

Created:任务已经初始化,但尚未进入调度计划

WaitingForActivation:该任务已进入调度计划,正在等待被调度程序激活

WaitingToRun:该任务已被调度程序激活,但尚未开始执行

Running:该任务正在运行,但尚未完成

RanToCompletion:该任务已经成功完成

Canceled:该任务由于被取消而完成,引发异常或调用方已向该任务的CancellationToken发出信号

Faulted:该任务因为出现未经处理的异常而完成

WaitingForChildrenToComplete:该任务本身已完成,正等待附加的子任务完成

  任务完成情况相关的属性有IsCompleted、IsCanceled和IsFaulted等属性,从单词意思上看不难理解它们的意思,其中要注意IsCompleted属性表示任务是否完成,无论是正常结束还是因为取消或异常而完成都为完成。

5. 任务执行的进度

  有时候我们希望让某些异步操作提供进度通知,以便在界面中显示异步操作执行的进度,可以用Progress<T>类来得到任务执行的进度。以下是利用方法里的Report方法将方法内变量的值传回创建任务的事件代码里,从而更新进度条的值。

     CancellationTokenSource cts;
private async void button3_Click(object sender, EventArgs e)
{
progressBar1.Maximum = 100;
progressBar1.Value = 0;
cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;
var pp = new Progress<int>();
pp.ProgressChanged += (s, n) => {
progressBar1.Value = n;
};
var tt = Task.Run(()=>MYThreadAsync(pp,cts.Token,500),cts.Token);
try
{
await tt;
if (tt.Exception == null)
listBox1.Items.Add("任务完成");
}
catch (Exception ex)
{
listBox1.Items.Add("异常" + ex.Message);
}
}
private void button4_Click(object sender, EventArgs e)
{
cts.Cancel();
}
public void MYThreadAsync(IProgress<int> progress, CancellationToken ct, int delay)
{
int p = 0;//进度
while (p < 100 && ct.IsCancellationRequested == false)
{
p += 1;
Thread.Sleep(delay);
progress.Report(p);//这个方法将会触发ProgressChanged事件更新进度条
}
}

6. 定时完成任务

  无论是服务器还是客户端,都是有定时完成某个 任务的需要的。System.Timers.Timer类是一个不错的定时设置类,这个类可以引发事件,但它默认是在线程池中引发事件,而不是在当前线程 中引发事件。Timer类的常用属性有AutoReset和Interval属性,AutoReset是获取或设置一个bool值,该值为true表示每 次间隔结束时都引发一次Elapsed事件,false表示仅在首次间隔结束时引发一次该事件。Interval属性是获取或设置两次Elapsed事件 的间隔时间,该值必须大于零并小于Int.MaxValue,默认值为100毫秒。Timer类还有两个常用方法那就是Start和Stop方法。

  还有一个 System.Threading.Timer类,它也是在线程池中定时执行任务,它与前一个Timer类的区别是该类不使用事件模型,而是直接通过 TimerCallback类型的委托来实现的。该类的构造函数为:Timer(TimerCallback callback,Object state,TimeSpan douTime,TimeSpan period)。callback表示要执行的方法,state表示一个包含回调方法要使用的信息的对象,dueTime是首次调用回调方法之前延迟的时 间,period表示每次调用回调方法的时间间隔,-1表示终止。这样创建对象后,首次到达dueTime延时时间会自动调用一次callback委托, 以后每隔period时间间隔调用一次。以下是这两种方式的运行效果和源代码。

     System.Timers.Timer timer;
System.Threading.Timer threadtimer;
private void button2_Click(object sender, EventArgs e)//Timers.Timer
{
progressBar1.Maximum = 100;
progressBar1.Value = 0;
int pro=0;
timer = new System.Timers.Timer(500);
timer.AutoReset = true;
timer.Elapsed+= (obj, args) =>
{
pro+=5;
progressBar1.Value = pro;
};
timer.Start();
} private void button5_Click(object sender, EventArgs e)
{
timer.Stop();
listBox1.Items.Add("第一个已经停止");
}
    //Threading.Timer类
private void button1_Click(object sender, EventArgs e)
{
progressBar2.Maximum = 100;
progressBar2.Value = 0;
TimeSpan dueTime = new TimeSpan(0, 0, 0, 1);
TimeSpan period = new TimeSpan(0, 0, 0, 0, 200);
System.Threading.TimerCallback timecall = new TimerCallback((obj) => progressBar2.Value += 5);
threadtimer = new System.Threading.Timer(timecall, null, dueTime, period);
} private void button6_Click(object sender, EventArgs e)
{
threadtimer.Dispose();
listBox1.Items.Add("第二个已经停止");
}

  这篇文章只总结了单个任务的异步执行的基础,还得继续学习多任务并行执行。如果有更好的技术或者与企业使用相关的异步技术,希望园友可以提出我继续学习。

C#异步编程 z的更多相关文章

  1. 异步编程 z

    走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...

  2. .Net异步编程 z

    1. 引言 最近在学习Abp框架,发现Abp框架的很多Api都提供了同步异步两种写法.异步编程说起来,大家可能都会说异步编程性能好.但好在哪里,引入了什么问题,以及如何使用,想必也未必能答的上来. 自 ...

  3. ASP.Net Core异步编程

    ASP.Net Core异步编程 概念 什么是异步编程? 异步编程是可以让程序并行运行的一种手段,其可以让程序中的一个工作单元与主应用程序线程分开独立运行,并且在工作单元运行结束后,会通知主应用程序线 ...

  4. 使用Async和Await进行异步编程(C#版 适用于VS2015) z

    你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net F ...

  5. C# 异步编程小结

    APM 异步编程模型,Asynchronous Programming Model EAP 基于事件的异步编程模式,Event-based Asynchronous Pattern TAP 基于任务的 ...

  6. C#~异步编程再续~你必须要知道的ThreadPool里的throw

    问题依旧存在 之前写过相关文章异步编程的文章,本文主要还是一点补充,之前在IIS经常发w3wp进程无做挂了的情况,但一直没能找到真正的原因,而查找相关资料,找了一些相关的文章,如await和async ...

  7. C#异步编程(一)

    异步编程简介 前言 本人学习.Net两年有余,是第一次写博客,虽然写的很认真,当毕竟是第一次,肯定会有很多不足之处, 希望大家照顾照顾新人,有错误之处可以指出来,我会虚心接受的. 何谓异步 与同步相对 ...

  8. C#与C++的发展历程第三 - C#5.0异步编程巅峰

    系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...

  9. 关于如何提高Web服务端并发效率的异步编程技术

    最近我研究技术的一个重点是java的多线程开发,在我早期学习java的时候,很多书上把java的多线程开发标榜为简单易用,这个简单易用是以C语言作为参照的,不过我也没有使用过C语言开发过多线程,我只知 ...

随机推荐

  1. 使用substring和split方法从字符串中抽取一组清单

    提取前: '这是一个句子.这是一个句子,包含了一列清单: 樱桃, 橙子, 桔子, 苹果, 香蕉.这是清单内容.'; 提取后: ["樱桃", " 橙子", &qu ...

  2. VS产生sdf和ipch文件太大处理方案

    方法: 工具-->选项-->文本编辑器-->C/C++-->高级-->回退位置,把始终使用回退位置设置为true,回退位置已在使用,不警告也设置为true,回退位置设置为 ...

  3. 模仿ViewPager控件

    自定义控件是开发中经常使用的技术.系统中自带的ViewPager实现的功能有时候不能满足开发的需要,如ViewPager没有滑动图片时的动画切换效果.通过对 ViewPager的模仿和部分功能的加强, ...

  4. 转 -Linux 自检和 SystemTap (强大的内核调试工具)---包含下载地址

    下载: http://www.oschina.net/p/systemtap/ https://sourceware.org/systemtap/ftp/releases/   Linux 自检和 S ...

  5. 从开发的角度比较 ASP.NET Web 服务与 WCF

    Windows Communication Foundation (WCF) 具有一个 ASP.NET 兼容模式选项,用户使用此选项可以对 WCF 应用程序进行编程和配置,使其像 ASP.NET We ...

  6. SQL 将一列多行数据合并为一行 FOR XML PATH

    FOR XML PATH 方法是用于将查询结果集以XML形式展示,这样展示方式的好处不言而喻.现在我要介绍的FOR XML PATH的"另类"用法. 首先,我们先来看看它的正常用法 ...

  7. 使用Myeclipse 2015 进行 Hdp 4 windows 开发

    在本地环境下进行开发,使用cygwin安装 Hdp那就是一个呵呵岂能概括. 所以啊,还是用Hdp windows进行开发测试吧.这样感觉省心点.具体 Hdp windows的安装参看前面的文章或自行G ...

  8. SqlParameter设定的value值为0时、调用的存储过程获取到的值却为null解决方法

    原C#代码如下: if (query != null) { switch (query.MethodFlag) { //进出口退补税额统计表 case (int)EnumClassifyCorrect ...

  9. Hibernate3回顾-4-事务和并发管理

    4.事务和并发 Hibernate是对JDBC的轻量级对象封装,Hibernate本身是不具备Transaction处理功能的,Hibernate的Transaction实际上是底层的JDBC Tra ...

  10. 09Socket编程

    tcp是基于字节流的,udp是基于报文即数据包的,所以tcp会产生一个叫做粘包的问题,而udp不会产生. 我们这节主要讨论粘包问题: 先看一下粘包问题的原因: 总结如下: 1.应用进程的缓冲区和Soc ...