多线程异步编程示例和实践-Task
上篇博文中,我们介绍了Thread和ThreadPool:
多线程异步编程示例和实践-Thread和ThreadPool
本文中我们继续,说一下TPL(Task Parallel Library, 简称TPL)。
在实际的开发中,使用线程池相当复杂,线程的异常捕获、传递以及编排这些问题实现起来都很复杂。
从 .NET Framework 4 开始,TPL 是编写多线程代码和并行代码的首选方法。顾名思义,任务并行库 (TPL) 基于任务的概念。 术语“任务并行”是指一个或多个独立的任务同时运行。 任务表示异步操作,在某些方面它类似于创建新线程或 ThreadPool 工作项,但抽象级别较高。 任务的提供有两个主要好处:
1). 系统资源的使用效率更高,可伸缩性更好。
在后台,任务排队到 ThreadPool,ThreadPool 已使用登山等算法进行增强,这些算法能够确定并调整到可最大化吞吐量的线程数。 这会使任务相对轻量,可以创建很多任务,启用细化并行
2). TPL提供了一组简单丰富的 API,这些 API 支持等待、取消、继续、可靠的异常处理、详细状态、自定义计划等功能。降低多线程编码和并行编程的复杂度,提升开发效率。
1. 创建和运行任务
多次执行,输出结果:
上面的示例中,创建和运行任务有两种方式:
- 创建任务->启动任务,Start立即执行
- 直接创建并启动任务
多次运行,发现两种执行结果,为什么?
task1和task2的任务都被放置在线程池的工作者线程中,任务的执行顺序是不确定的。
2. 取消任务
关键的对象:CancellationToken
测试代码:
运行输出:
3. 创建任务集合并输出结果
关键知识点:
- Task支持返回值:Task<T>
- 获取Task的返回值:Task.Result
Task.Result操作意味着什么?等待Task异步调用完成,从效果上等同于Wait方法
4.处理任务异常
测试代码:
运行输出:
关键知识点:
- 通过Catch捕获Task的异常是AggregateException,一个被封装的异常,需要通过InnerException访问底层异常
- 推荐使用GetWaiter和GetResult方法访问Task的结果,可以获取到原始异常;
- 通过ContinueWith处理OnlyOnFaulted事件,捕获的异常也是一个被封装的异常,需要通过InnerException访问底层异常
5. 多任务的串行化
关键知识点:
- Task.ContinueWith
- Task逐层传递
- 第一个任务Start启动即可,不需要全部任务启动。
6. 多任务等待执行完成
多次执行输出:
关键知识点:
- Task.WaitAll
- Task执行顺序是随机的,线程池机制(两种调度算法)
8. 创建子任务
关键知识点:
- TaskCreationOptions.AttachedToParent
- 除非所有子任务(子任务的子任务)结束运行,否则创建任务(父任务)不会认为已经结束
- 父任务异常不会影响子任务执行
- 子任务异常不会影响父任务执行
9. 补充一个知识点:前台线程和后台线程
应用程序必须运行完所有的前台线程才可以退出;
对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
那么,Thread、线程池的线程、Task都各自属于哪一类线程?
- 使用Thread建立的线程默认情况下是前台线程,即线程属性IsBackground=false.
- 属于托管线程池的线程(即其 IsThreadPoolThread 属性为 true 的线程)是后台线程
- Task都是后台线程:Task需要在其运行过程中至少有一个前台线程在跑,否则会直接退出.
准备再写一篇博客,分享几个多线程异步我们踩过的坑和解决方法。
周国庆
2017/6/9
多线程异步编程示例和实践-Task的更多相关文章
- 多线程异步编程示例和实践-Thread和ThreadPool
说到多线程异步编程,总会说起Thread.ThreadPool.Task.TPL这一系列的技术.总结整理了一版编程示例和实践,分享给大家. 先从Thread和ThreadPool说起: 1. 创建并启 ...
- 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
[源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...
- C#——await与async实现多线程异步编程
曾经,我们也许用过Thread.在主线程运行的时候.新开还有一个新线程,来运行新方法. 今天看别人发给我的一段代码的时候发现了一个不认识的await,可是又感觉非常熟悉的样子,感觉是线程那块儿的东西, ...
- 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...
- .Net 多线程 异步编程 Await、Async和Task
await和async简介 await和async是在C#5中引入,并且在.NetFramewor4.5以及.NetCore中进行了支持.主要是解决性能瓶颈,并且增强系统的响应能力. msdn关于 ...
- [.net 多线程]异步编程模式
.NET中的异步编程 - EAP/APM 从.NET 4.5开始,支持的三种异步编程模式: 基于事件的异步编程设计模式 (EAP,Event-based Asynchronous Pattern) 异 ...
- C#异步编程之浅谈Task
上一篇讲到了.Net4.5新增的async和await关键字,其实async和await算是一组标记,真正实现异步操作的是Task新开的任务线程. 什么是Task Task是.Net4.0新增用来处理 ...
- 多线程socket编程示例
工程: 代码: package com.my.socket.business; /** * 业务实现类 * * @author ZY * */ public class CoreMisBusiness ...
- 实践-Task
实践-Task 上篇博文中,我们介绍了Thread和ThreadPool: 多线程异步编程示例和实践-Thread和ThreadPool 本文中我们继续,说一下TPL(Task Parallel Li ...
随机推荐
- Go语言及Web框架Beego环境
Go语言及Web框架Beego环境无脑搭建 [原]Go语言及Web框架Beego环境无脑搭建 本文涉及软件均以截至到2013年10月12日的最新版本为准 1. 相关软件准备: 1) go1.2rc1. ...
- docker.service启动失败:Unit not found
docker.service启动失败:Unit not found 版权声明:本文为博主原创文章,未经博主允许不得转载. 背景 因为最近一直在折腾Kubernetes集群版本升级.Docker版本升级 ...
- HTML5 进阶系列:indexedDB 数据库
前言 在 HTML5 的本地存储中,有一种叫 indexedDB 的数据库,该数据库是一种存储在客户端本地的 NoSQL 数据库,它可以存储大量的数据.从上篇:HTML5 进阶系列:web Stora ...
- IIS发布mvc程序遇到的HTTP错误 403.14-Forbidden解决办法
在IIS上发布MVC应用程序后,在浏览器查看时会报如下图的错误: 这时,我们首先检查一下“处理程序映射”,看一下里面是否有“ExtensionlessUrlHandler-Integrated-4.0 ...
- bzoj4784 [Zjoi2017]仙人掌
Description 如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌.所谓简单环即不经过重复的结点的环. 现在九条可怜手上有一张无自环无重边的无向连通图,但是她觉得 ...
- MyEclipse(8.5以上的版本) 安装js的开发插件aptana
最近在学习js,想在MyEclipse(MyEclipse 10) 上面安装一个js的开发的插件aptana. MyEclipse 8.5以后的版本的安装的方法: 1.下载aptana_update_ ...
- JQuery 中关于插入新元素的方法
关于JQuery插入新内容的方法: append() - 在被选元素的结尾插入内容 prepend() - 在被选元素的开头插入内容 after() - 在被选元素之后插入内容 before() - ...
- 【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 F - Piggy-Bank 【完全背包问题】
https://vjudge.net/contest/68966#problem/F http://blog.csdn.net/libin56842/article/details/9048173 # ...
- 记录下一个C++初始化的方式(很少有人这么用,但是却是一个使代码更加简洁的方式)
很多时候,在一个类创建的时候给它初始化,一般呢,99%的人都会这么用: //A.h Class CA { int a; char* p; int getValue(); }; //A.cpp CA:: ...
- 'k1': 大于66的所有值, 'k2': 小于66的所有值
#!/usr/bin/env python # -*- coding: utf-8 -*- #有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值 ...