上一篇简单讲解了 线程和线程池以及上下文切换。创建线程代价高昂,默认每个线程都要占用大量虚拟内存1M。更有效的做法使用线程池,重复利用线程。在.NET4.0中引入了TPL任务并行库,你可以在将精力集中于程序要完成的工作,同时最大程度地提高代码的性能。在C#5.0中引入了async 和 await关键字,基于任务的异步模式(TAP),所以了解Task对后面学习异步操作会简单些。

任务是封装了以异步方式执行的工作。当启动一个任务,控制几乎立即返回调用者,无论任务要执行多少工作。

创建Task任务

有三种创建方式

  • 使用task构造函数
  • task工厂类静态方法
  • 使用.NET4.5新引入的Task.run()。

我们创建一个输出300万个32位字符的GUID任务分别使用三种不同方式实现。代码如下 constint RepeatCount = ; //重复次数

            var listGuid = new BlockingCollection<string>();

            //Action无返回值
Action dowork = () =>
{
for (var count = ; count < RepeatCount; count++)
{
listGuid.Add(Guid.NewGuid().ToString("N"));
}
};
Task task1 = new Task(dowork); //1)使用构造函数
task1.Start();
Task task2 = Task.Factory.StartNew(dowork); //2)Task工厂方法,直接运行,不需要在调用start()
Task task3 = Task.Run(dowork); //3)4.5 Task.Run 是Task.Factory.StartNew简化方式;直接运行,不需要在调用start() Task.WaitAll(task1, task2, task3); //等待所有任务完成,相当于 thread.join()
Console.Write($"生成数量:{listGuid.Count / 10000}万");

输出

上述实例创建一个没有返回值的任务,当然也可以通过Task<TResult> 来创建返回值的异步操作。

连续任务

第一个任务生成32位字符的Guid任务,利用返回的结果再转化成对应的ASCII码,最后ASCII码十进制的值相加。代码如下

 //Func
Func<string> doWork = () =>
{
return Guid.NewGuid().ToString("N");
};
//延续任务
var task = Task.Run(doWork).ContinueWith(async strGuid =>
{
var resut = await strGuid;
var array = Encoding.ASCII.GetBytes(resut); int mLenght = array.Length;
int sumResult = ;
for (int m = ; m < mLenght; m++)
{
sumResult += array[m];
}
Console.WriteLine($"Guid对应10进制相加结果:{sumResult}");
});

输出

处理任务异常

同步代码要想捕获异常,只需在代码块上添加Try ...Catch即可。但是异步调用不能这么做。因为控制会立即从调用返回,然后控制会离开Try块,而这时距离工作者线程发生异常可能还有好久呢。

为了处理出错的任务,一个技术是显式创建延续任务作为那个任务的“错误处理程序”。检测到先驱任务引发未处理的异常,任务调度器会自动调度延续任务。但是,如果没有这种处理程序,同时在出错的任务上执行wait()(或其他试图获取result的动作),就会引发一个AggregateException,示例代码如下。

  Task task = Task.Run(() =>
{
throw new InvalidOperationException();
}); try
{
task.Wait();
}
catch (Exception ex)
{
Console.WriteLine($"常规erro:{ex.Message};type:{ex.GetType()}");
AggregateException excetion = (AggregateException)ex;
excetion.Handle(eachException =>
{
Console.WriteLine($"erro:{eachException.Message}");
return true;
});
}

输出

虽然工作者线程上已发的未处理异常是InvalidOperationException类型,但主线程捕捉的仍是一个AggregateException。由于编译时不知道工作者任务将要引发一个还是多个异常,所以未处理的出错任务总是引发一个AggregateException。

还可查看任务的Exception属性来了解出错任务的状态,这样不会造成在当前线程上重新引发异常。代码如下

  bool paraentTaskFaulted = false;
Task task = new Task(() =>
{
throw new InvalidOperationException();
}); Task continuationTask = task.ContinueWith(t =>
{ paraentTaskFaulted = t.IsFaulted;
}, TaskContinuationOptions.OnlyOnFaulted); task.Start();
Console.Write(continuationTask.Status);
continuationTask.Wait();
//如果断言失败 则显示一个消息框,其中显示调用堆栈。
Trace.Assert(paraentTaskFaulted);
if (!task.IsFaulted)
{
task.Wait();
}
else
{
task.Exception.Handle(eachException =>
{
Console.WriteLine($"erro:{eachException.Message}");
return true;
});
}

注意,为了获取原始任务上的未处理异常,我们使用Exception属性。结果和上面示例输出一样。

取消任务

任务支持取消,比如常用在指定时间内的任务或者基于某些条件手动的取消,支持取消的任务要监听一个CancellationToken对象。任务轮询它,检查是否出发了取消请求。如下代码展示了取消请求和对请求的响应。

 /// <summary>
/// 取消任务
/// </summary>
public void TaskTopic5()
{
string stars = "*".PadRight(Console.LargestWindowWidth-,'*');
Console.WriteLine("push enter to exit.");
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); //向应该被取消的 System.Threading.CancellationToken 发送信号
Task task = Task.Run(
()=>
Count(cancellationTokenSource.Token,),
cancellationTokenSource.Token); Console.Read();
cancellationTokenSource.Cancel();//按下enter键, 传达取消请求 Console.WriteLine(stars);
Console.WriteLine(task.IsCanceled);
task.Wait();
Console.WriteLine();
}
/// <summary>
/// 数数
/// </summary>
/// <param name="token"></param>
/// <param name="countTo"></param>
private void Count(CancellationToken token,int countTo)
{
for (int count = ; count < countTo; count++)
{
//监控是否取消
if (token.IsCancellationRequested)
{
Console.WriteLine("数数喊停了");
break;
} Console.Write(count+"=》");
Thread.Sleep(TimeSpan.FromSeconds());
}
Console.WriteLine("数数结束");
}

输出

调用Cancel()实际会在从cancellationTokenSource.Token复制的所有取消标志上设置IsCancellationRequested属性。

到此任务的一些基本的操作已经完成了,下一节关注下C#5.0的async/await上下文关键字。

对话Task的更多相关文章

  1. 基于人工智能标记语言 (AIML)和任务型对话系统(Task)的深度智能对话机器人demo

    起因 本demo基于基于人工智能标记语言 (AIML)和开放域问答(WebQA)的深度智能对话模型而来 无意间发现一个基于人工智能标记语言 (AIML)和开放域问答(WebQA)的深度智能对话模型,但 ...

  2. 在Dynamics 365中使用SURVEYJS代替对话(Dialog)制作话术

    本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复269或者20180318可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me ...

  3. C#并行开发_Thread/ThreadPool, Task/TaskFactory, Parallel

    大家好,本次讨论的是C#中的并行开发,给力吧,随着并行的概念深入,哥也赶上这个潮流了,其实之前讨论C#的异步调用或者C#中BeginInvoke或者Invoke都已经涉及了部分本篇的内容. 参考书目: ...

  4. 手把手教你利用微软的Bot Framework,LUIS,QnA Maker做一个简单的对话机器人

    最近由于要参加微软亚洲研究院的夏令营,需要利用微软的服务搭建一个对话Bot,以便对俱乐部的情况进行介绍,所以现学了几天,搭建了一个简单的对话Bot,期间参考了大量的资料,尤其是下面的这篇博客: htt ...

  5. 下一个时代,对话即平台 —— 开始使用Bot Framework和Cognitive Service来打造你的智能对话服务

    在16年3月30号微软的全球开发者大会Build上发布了Bot Framework,微软认为下一个big thing是Conversation as a Platform,简称CaaP,中文应该叫做& ...

  6. 学习笔记(5)- ubuntu对话语料

    The Ubuntu Dialogue Corpus: A Large Dataset for Research in Unstructured Multi-Turn Dialogue Systems ...

  7. 一句 Task.Result 就死锁, 这代码还怎么写?

    一:背景 1. 讲故事 前些天把 .NET 高级调试 方面的文章索引到 github 的过程中,发现了一个有意思的评论,详见 文章,截图如下: 大概就是说在 Winform 的主线程下执行 Task. ...

  8. BERT生成能力改进:分离对话生成和对话理解

    NLP论文解读 原创•作者 | 吴雪梦Shinemon 研究方向 | 计算机视觉 导读说明: NLP任务大致可以分为NLU(自然语言理解)和NLG(自然语言生成)两种,NLU负责根据上下文去理解当前用 ...

  9. Concepts:Request 和 Task

    当SQL Server Engine 接收到Session发出的Request时,SQL Server OS将Request和Task绑定,并为Task分配一个Workder.在TSQL Query执 ...

随机推荐

  1. java_19List 集合

    1List集合 有序的 collection(也称为序列).此接口的用户可以对列表中每个元素的插入位置进行精确地控制.用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素. 与 s ...

  2. 如何在3GPP下载协议

    以下载AT Commands协议为例. 1. 打开3GPP网址:http://www.3gpp.org/ 2. 打开Specification-Specification Numbering,如图.去 ...

  3. tab选项卡实例

    之前也见了不少的tab选项卡,但是下面这个选项卡是一个页面中有多个时互不影响的. <head> <meta charset="utf-8"> <met ...

  4. 使用注解配置Spring

    使用注解配置Spring 1.为主配置文件引入新的命名空间(约束) 2.开启使用注解代理配置文件 3.在类中使用注解完成配置 将对象注册到容器 修改对象的作用范围 值类型注入 引用类型注入 注意: 初 ...

  5. 机器学习面试--一句话概括传统ML算法

    机器学习过程主要包括:数据的特征提取.数据预处理.训练模型.测试模型.模型评估改进等几部分 传统机器学习算法主要包括以下五类: 回归:建立一个回归方程来预测目标值,用于连续型分布预测 分类:给定大量带 ...

  6. Linux 第五天

    网络命令 1)write 给在线用户发信息(需按Crtl+D保存结束,w命令可看在线用户) 语法:write 用户名 2)wall 发广播信息 英文原意:write all 语法:wall 信息 3) ...

  7. boost-字符文本处理

    1.lexical_cast 一些常见的数值,字符互转函数: 整型int: itoa()._itoa_s atoi()._ttoi 无符号整型unsigned int: _ultoa_s()._ult ...

  8. 20155339 Exp9 Web安全基础

    Exp9 Web安全基础 基础问题回答 (1)SQL注入攻击原理,如何防御 原理:它是利用现有应用程序,将恶意的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入恶意SQL语句得到 ...

  9. Chapter5 生长因子、受体和癌症

    一.Src蛋白是一种蛋白激酶 可以磷酸化不同的底物,调节不同的通路 Src激酶主要磷酸化酪氨酸残基,而别的激酶主要磷酸化色氨酸.苏氨酸残基 二.EGF受体拥有酪氨酸激酶功能 胞内结构域有Src蛋白的同 ...

  10. Forward团队-爬虫豆瓣top250项目-模块测试

    项目托管平台地址:https://github.com/xyhcq/top250 模块测试:爬虫对信息的处理部分 测试方法: 实际运行一下代码: 可以看见,信息都已经爬取出来了 其他补充说明: 原本系 ...