C# 异步编程3 TPL Task 异步程序开发
.Net在Framework4.0中增加了任务并行库,对开发人员来说利用多核多线程CPU环境变得更加简单,TPL正符合我们本系列的技术需求。因TPL涉及内容较多,且本系列文章为异步程序开发,所以本文并未涉及TPL全部内容。后续会写一个TPL系列的Blog,各位朋友可以关注一下。
TASK
TPL的基础Task,Task是TPL并行编程的最小单元,即表示一个异步操作。利用Task进行异步编程非常简单:
static void Main(string[] args)
{
BaseTaskDemo();
//BaseTaskDemo2();//两者效果相同
Console.WriteLine(String.Format("Main 线程:{0}", Thread.CurrentThread.ManagedThreadId));
Console.ReadLine();
}
private static void BaseTaskDemo()
{
var task = new Task(() => {
Thread.Sleep();
Console.WriteLine(String.Format("Task 线程:{0}", Thread.CurrentThread.ManagedThreadId));
});
task.Start();
}
private static void BaseTaskDemo2()
{
var task = Task.Run(() =>
{
Thread.Sleep();
Console.WriteLine(String.Format("Task 线程:{0}", Thread.CurrentThread.ManagedThreadId));
});
}
程序说明:
1、new Task(Action)创建一个异步任务,参数Action是异步任务要执行的委托对象
2、task.Start()启动异步任务的执行
3、Task.Run(Action)等效于1、2的组合
上面的示例程序实现了异步操作,但主线程无法获知异步任务完成与否。为获取Task的执行结果,上面的程序进行如下修改:
static void Main(string[] args)
{
var task = TaskForResult();
Console.WriteLine(String.Format("Main 线程:{0}", Thread.CurrentThread.ManagedThreadId));
task.Wait();
if (task.IsCompleted)
Console.WriteLine(String.Format("获取异步执行结果:{0}", task.Result));
Console.ReadLine();
}
private static Task<int> TaskForResult()
{
var task = Task.Run(()=> {
Thread.Sleep();
Console.WriteLine(string.Format("Task 线程:{0},Task执行完成。", Thread.CurrentThread.ManagedThreadId));
return ;
});
return task;
}
程序说明:
1、下面代码的原型为Task.Run(Func<int>),Run的参数不再是Action,因为在该任务中我们要返回一个int值,所以应该使用Run(Func<T>)这个重载。
var task = Task.Run(()=> {
Thread.Sleep(2000);
Console.WriteLine(string.Format("Task 线程:{0},Task执行完成。", Thread.CurrentThread.ManagedThreadId));
return 10;
});
2、主线程中调用task.Wait()时,主线程将一直等待异步任务完成或被取消。
3、task.IsCompleted属性用于判断异步任务是否完成
4、task.Result获取异步任务的执行结果(返回值)
上面的示例程序已经实现了主线程获取异步程序的状态及返回值,但如果异步程序非常耗时,则存在主线程需要临时取消耗时异步程序执行的功能。为了满足上述要求,程序可做如下调整:
static void Main(string[] args)
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
var task = TaskForResult2(tokenSource);
Console.WriteLine(String.Format("Main 线程:{0}", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine(String.Format("Main 线程:{0},获取异步执行结果:{1}", Thread.CurrentThread.ManagedThreadId, task.Result));
Console.ReadLine();
}
private static Task<int> TaskForResult2(CancellationTokenSource tokenSource)
{
var task = Task.Run(() =>
{
Thread.Sleep();
if (!tokenSource.IsCancellationRequested)
{
Console.WriteLine(String.Format("Task 线程:{0},任务1执行完成。", Thread.CurrentThread.ManagedThreadId));
return ;
}
else
{
return -;
}
}, tokenSource.Token);
return task;
}
程序说明:
1、CancellationTokenSource提供任务取消消息,构造参数 5000 表示CancellationTokenSource在发出5s后超时并取消
2、在Task的委托内部 tokenSource.IsCancellationRequested 获取取消标记
3、task.Result会隐式调用Wait()方法
如果异步Task在执行过程中出现异常,则需要对发生的异常做出响应:
static void Main(string[] args)
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
var task = TaskForResult2(tokenSource);
Console.WriteLine(String.Format("Main 线程:{0}", Thread.CurrentThread.ManagedThreadId));
try
{
//task.Wait();
Console.WriteLine(String.Format("Main 线程:{0},获取异步执行结果:{1}", Thread.CurrentThread.ManagedThreadId, task.Result));
}
catch (AggregateException ex)
{ }
Console.ReadLine();
}
private static Task<int> TaskForResult2(CancellationTokenSource tokenSource)
{
var task = Task.Run(() =>
{
Thread.Sleep();
if (!tokenSource.IsCancellationRequested)
{
throw new Exception("抛出异常");
}
else
{
return -;
}
}, tokenSource.Token);
return task;
}
程序说明:
1、在Task中引发的异常需要在 task.Wait()或task.Result时捕获
写在后面:Task的功能远不止上述这些,如Task多任务串行、TaskFactory、Paralle等知识非常有趣和重要。如果你感兴趣的话,可以关注本人后续TPL的文章。
C# 异步编程3 TPL Task 异步程序开发的更多相关文章
- C# 异步编程1 APM模式异步程序开发
C#已有10多年历史,单从微软2年一版的更新进度来看活力异常旺盛,C#中的异步编程也经历了多个版本的演化,从今天起着手写一个系列博文,记录一下C#中的异步编程的发展历程.广告一下:喜欢我文章的朋友,请 ...
- 搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文
你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...
- Linux网络编程:基于UDP的程序开发回顾篇
基于无连接的UDP程序设计 同样,在开发基于UDP的应用程序时,其主要流程如下: 对于面向无连接的UDP应用程序在开发过程中服务端和客户端的操作流程基本差不多.对比面向连接的TCP程序,服务端少了 ...
- Linux网络编程:基于TCP的程序开发回顾篇《转》
面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你 ...
- 深入理解JS异步编程五(脚本异步加载)
异步脚本加载 阻塞性脚本 JavaScript在浏览器中被解析和执行时具有阻塞的特性,也就是说,当JavaScript代码执行时,页面的解析.渲染以及其他资源的下载都要停下来等待脚本执行完毕 浏览器是 ...
- C# 异步编程2 EAP 异步程序开发
在前面一篇博文记录了C# APM异步编程的知识,今天再来分享一下EAP(基于事件的异步编程模式)异步编程的知识.后面会继续奉上TPL任务并行库的知识,喜欢的朋友请持续关注哦. EAP异步编程算是C#对 ...
- .Net Core WebAPI 基于Task的同步&异步编程快速入门
.Net Core WebAPI 基于Task的同步&异步编程快速入门 Task.Result async & await 总结 并行任务(Task)以及基于Task的异步编程(asy ...
- 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]
看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...
- Async 、 Await 的异步编程(.NET 4.5 新异步模型) [转自MSDN]
使用异步编程,可以避免性能瓶颈和增强应用程序的总体响应能力. 但是,编写异步应用程序的以前的技术可能比较复杂,使它们难以编写,调试和维护. Visual Studio 2012 引入了一个简化的方法, ...
随机推荐
- python(30)——【random模块】【if __name__ =='__main__'】【os模块】
一.random模块(随机模块) 1.random 常用模块介绍 import random print(random.random()) #返回[0,1)之间的随机浮点数 print(random. ...
- 测试工具之Jmeter(创建一个简单测试用例)
前面介绍了如何使用badboy录制jmeter脚本,以及如何导入脚本并进行测试 这里介绍下手动创建测试用例,主要步骤如下: 1.创建线程组 第一次打开Jmeter只有一个测试计划,右键“测试计划”选择 ...
- Jenkins系列之一——初识
Jenkins Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 功能 Jenkins功能包括 ...
- C#单元测试分享ppt
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证.对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类, ...
- 安装clickhouse缺少依赖libicudata.so.50()(64bit)
root@localhost ]# rpm -ivh clickhouse-common--.el7.x86_64.rpm 错误:依赖检测失败: libicudata.so.()(64bit) 被 c ...
- Struts的FormFile与Commons-FileUpload控件使用心得
转自: http://www.iteye.com/topic/212566 前一段时间刚来公司,看到一个项目中以前有人写的struts代码.是使用了FormFile来处理关于文件上传的模块.但是用力一 ...
- python subprocess模块详解
一.subprocess标准库 python执行shell脚本,通常会使用so模块中的几个方法,如system.spawn*.popen等.subprocess标准库的引入就是为了取代这些老的模块方法 ...
- Python vtk学习(1)
Vtk,(visualization toolkit)是一个开源的免费软件系统,主要用于三维计算机图形学.图像处理和可视化.Vtk是在面向对象原理的基础上设计和实现的,它的内核是用C++构建的,包含有 ...
- 使用Asp.Net Core MVC 开发项目实践[第一篇:项目结构说明]
先从下图看整体项目结构: Mango.Manager: 为后台管理项目 Mango.Web: 为前台项目 Mango.Framework.Core: 为常用的基础操作类项目 Mango.Framewo ...
- SQL Server重置INDETITY的开始值
@@IDENTITY 和SCOPE_IDENTITY 返回在当前会话中的任何表内所生成的最后一个标识值.但是,SCOPE_IDENTITY 只返回插入到当前作用域中的值:@@IDENTITY 不受限于 ...