.Net多线程编程—Parallel LINQ、线程池
Parallel LINQ
1 System.Linq.ParallelEnumerable
重要方法概览:
1)public static ParallelQuery<TSource> AsParallel<TSource>(this IEnumerable<TSource> source);启用查询的并行化
2)public static ParallelQuery<TSource> AsOrdered<TSource>(this ParallelQuery<TSource> source);启用将数据源视为“已经排序”的处理方法,重写默认的将数据源视为“未经排序”的处理方法。只可以对由 AsParallel、ParallelEnumerable.Range和 ParallelEnumerable.Repeat 返回的泛型序列调用 AsOrdered。
3) public static ParallelQuery<TSource> WithExecutionMode<TSource>(this ParallelQuery<TSource> source, ParallelExecutionMode executionMode);设置查询的执行模式
4)public static double Average(this ParallelQuery<double> source);计算序列平均值
5) public static decimal? Max(this ParallelQuery<decimal?> source);计算序列最大值
6) public static decimal? Min(this ParallelQuery<decimal?> source);计算序列中最小值
7)public static decimal? Sum(this ParallelQuery<decimal?> source);求和
8)public static TResult Aggregate<TSource, TAccumulate, TResult>(this ParallelQuery<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector);对一个序列并行应用累加器函数。 将指定的种子值用作累加器的初始值,并使用指定的函数选择结果值。
9)public static ParallelQuery<TSource> WithCancellation<TSource>(this ParallelQuery<TSource> source, CancellationToken cancellationToken);设置要与查询关联的 System.Threading.CancellationToken。
10)public static ParallelQuery<TSource> WithDegreeOfParallelism<TSource>(this ParallelQuery<TSource> source, int degreeOfParallelism);设置要在查询中使用的并行度。
11)public static void ForAll<TSource>(this ParallelQuery<TSource> source, Action<TSource> action);对 source 中的每个元素并行调用指定的操作。
12)public static ParallelQuery<TSource> WithMergeOptions<TSource>(this ParallelQuery<TSource> source, ParallelMergeOptions mergeOptions);设置此查询的合并选项,它指定查询对输出进行缓冲处理的方式。
说明:
1)PLINQ实现了全部的LINQ操作符,并添加了部分并行操作符。
2)不论是并发集合或传统集合都可使用PLINQ。
3)默认情况下,执行PLINQ时,.NET尽量避免高开销并行化算法;若想强制并行执行,可使用ParallelExecutionMode.ForceParallelism。
4)根据可用内核数,PLINQ将接受的数据源分解为多份,然后在不同的内核上处理每一份。且对每一份的执行没有固定顺序。
5)PLINQ查询有延缓执行的效果,因此要捕获查询所产生的结果在被消费者消费时产生的异常。
6)Aggregate的重载方法之一可以将数据源序列分区成几个子序列(分区)。 对分区内的每个元素执行 updateAccumulatorFunc,得到每个分区的单个累积结果。 然后,在每个分区的结果上调用 combineAccumulatorsFunc 来产生一个元素。 最后,combineAccumulatorsFunc 产生的元素通过 resultSelector 函数进行转换即可获得最终结果。
2 使用示例
定义List<T> list = ......,代码中的condition为筛选条件。
1)排序
//确保运算获得的数据输出顺序与原集合一致
var resLinq1 = from item in list.AsParallel().AsOrdered()
where (condition)
select item;
var res1 = list.AsParallel().AsOrdered().Where(m=>m>);
//按升序排列使用ascending,降序排列使用descending
var resLinq2 = from item in list.AsParallel()
where (condition)
orderby item descending
select item; //升序排列使用OrderBy,降序排列使用OrderByDescending
var res2 = list.AsParallel().Where(item =>condition).OrderByDescending(m => m);
2)设置查询的执行模式
//强制并行化整个查询
var resLinq3 = from item in list.AsParallel().
WithExecutionMode(ParallelExecutionMode.ForceParallelism)
where (condition)
orderby item descending
select item; var res3 = list.AsParallel().
WithExecutionMode(ParallelExecutionMode.ForceParallelism).
Where(condition).OrderByDescending(m => m);
3)规约操作
假定这里的list中的元素为数字。
var resLinq4 = (from item in list.AsParallel()
where (condition)
select item).Average();
var res4 = list.AsParallel().Where(item => condition).Average(); var resLinq5 = (from item in list.AsParallel()
where (condition)
select item).Max();
var res5 = list.AsParallel().Where(item => condition).Max();
4)自定义聚集函数
假定这里的list中的元素为数字。
//方差计算公式:S2 = ((X1-A)2+(X2-A)2+...+(Xn-A)2)/N,其中A为平均值,N为序列中元素个数,Xi为序列中第i个元素
//sum 求和部分结果,item:集合list中的元素,result:经计算后得到的方差值。
var average = list.AsParallel().Average();
var res6 = list.AsParallel().Aggregate(
0d,
(sum, item) => sum + Math.Pow((item - average),),
(result)=>result/list.Count
);
//与上面结果相同,只不过多了combineAccumulatorsFunc函数
var res7 = list.AsParallel().Aggregate(
0d,
(sum, item) => sum + Math.Pow((item - average), ),
(total,thisTask)=>total+thisTask,
(result) => result / list.Count
5)取消并行操作
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;
CancelParallel(ct,list); private static void CancelParallel(CancellationToken ct,List<int> list)
{
//conditionExec此条件为真时才取消并行操作
if (conditionExec)
{
ct.ThrowIfCancellationRequested();
}
var average = list.AsParallel().Average();
list.AsParallel().WithCancellation(ct).Aggregate(
0d,
(sum, item) => sum + Math.Pow((item - average), ),
(total, thisTask) => total + thisTask,
(result) => result / list.Count
);
}
6)指定并行度
int maxDegreeOfParallelism = Environment.ProcessorCount;
var res8 = list.AsParallel().WithDegreeOfParallelism(maxDegreeOfParallelism).Aggregate(
0d,
(sum, item) => sum + Math.Pow((item - average), ),
(result) => result / list.Count
);
7)使用ForAll
ConcurrentBag<T> bag = new ConcurrentBag<T>();
list.AsParallel().ForAll(item =>
{
//对元素处理后加如集合
bag.Add(itemAfter);
});
8)异常处理
使用AggregateException处理异常,具体示例见Tasks.Parallel部分。
线程池
1 CLR 4线程池引擎与线程
- CLR线程池引擎管理着一个池的线程,这些线程可以处理工作项。线程池引擎会每隔一段时间创建出额外的空闲线程,这些空闲线程以FIFO的顺序将工作项从队列中取出,并且开始执行这些工作项。
- CLR线程池引擎创建一个托管线程需要数千CPU周期,并且消耗内存。
- CLR线程池引擎维护了最低数量的闲置工作线程,通常等于逻辑内核数。
- CLR线程池引擎管理的都是后台线程,即所有前台线程都退出了,后台线程不会维持应用程序继续运行。
2 全局队列与局部队列
- 使用使用TPL创建任务时,一个新的工作项会被加入到线程池全局队列中,当线程池中所有可用的工作线程都在执行工作项时,新加入线程池全局队列的工作相必须等待,直到有可用的工作项。
- 线程池中每一个分配给了任务的线程都有自己的局部队列,这样可以减少对全局队列的争用。局部对列通常以LIFO的顺序抽取任务并执行。
3 Threading.ThreadPool
与使用任务将工作项加入队列相比,创建Task实例有一定的开销,但可以利用一些取消标记等。
//使用QueueUserWorkItem方法将任务加入队列中。
ThreadPool.QueueUserWorkItem((state) => { //具体业务 });
//workerThreads线程池中辅助线程的最大数目,completionPortThreads线程池中异步 I/O 线程的最大数目
ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
//workerThreads线程池根据需要创建的最少数量的辅助线程
//completionPortThreads线程池根据需要创建的最少数量的异步 I/O 线程
ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
-----------------------------------------------------------------------------------------
转载与引用请注明出处。
时间仓促,水平有限,如有不当之处,欢迎指正。
.Net多线程编程—Parallel LINQ、线程池的更多相关文章
- java核心-多线程(6)-线程池-ThreadPoolExecutor
1.java多线程编程少不了使用线程池,线程池相关的工具类所在jdk包,java.util.concurrent 2.使用示例 demo1 public class ThreadPoolDemo { ...
- 第十章:Python高级编程-多线程、多进程和线程池编程
第十章:Python高级编程-多线程.多进程和线程池编程 Python3高级核心技术97讲 笔记 目录 第十章:Python高级编程-多线程.多进程和线程池编程 10.1 Python中的GIL 10 ...
- C#多线程之旅(3)——线程池
v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很 ...
- C# 多线程的自动管理(线程池) 基于Task的方式
C# 多线程的自动管理(线程池) 在多线程的程序中,经常会出现两种情况: 1. 应用程序中线程把大部分的时间花费在等待状态,等待某个事件发生,然后给予响应.这一般使用 ThreadPool(线程 ...
- 多线程(七)JDK原生线程池
如同数据库连接一样,线程的创建.切换和销毁同样会耗费大量的系统资源.为了复用创建好的线程,减少频繁创建线程的次数,提高线程利用率可以引用线程池技术.使用线程池的优势有如下几点: 1.保持 ...
- gj11 多线程、多进程和线程池编程
11.1 python中的GIL # coding=utf-8 # gil global interpreter lock (cpython) # python中一个线程对应于c语言中的一个线程 # ...
- Linux多线程实践(9) --简单线程池的设计与实现
线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...
- Java并发编程:Java线程池核心ThreadPoolExecutor的使用和原理分析
目录 引出线程池 Executor框架 ThreadPoolExecutor详解 构造函数 重要的变量 线程池执行流程 任务队列workQueue 任务拒绝策略 线程池的关闭 ThreadPoolEx ...
- java多线程系列六、线程池
一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池. 2. 使用线程池的好处 a) 降低资源的消耗.使用线程池不用频繁的创建线程和销毁线程 b) 提高响应速度,任 ...
随机推荐
- Sitemesh 3
Sitemesh 3 的使用及配置(收藏自:http://www.cnblogs.com/luotaoyeah/p/3776879.html) 1 . Sitemesh 3 简介 Sitemesh 是 ...
- IE/Chrome背景图片居中1px偏移解决方法
最近在支持行业运营的一个推广页面,遇到了非常规的页面banner图居中的问题,为了解决此问题,做了简单的测试,做了一个小结,为经常做大促页面的兄弟姐妹们提供参考解决方案. 首先来看看现象.最经典的页面 ...
- Apache+Tomcat服务器集群配置
在实际应用中,如果网站的访问量很大,为了提高访问速度,可以与多个Tomcat服务器与Apache服务器集成,让他们共同运行servlet/jsp 组件的任务,多个Tomcat服务器构成了一个集群(Cl ...
- Sping3.0版本+Quartz完成定时任务
----------------------不使用注解在XML中配置完成定时任务---------------------- 1.需要导入的jar包 2.编写我们的定时任务的完成类 3.在Spring ...
- 拦截asp.net输出流做处理, 拦截HTML文本(asp.net webForm版)
对已经生成了HTML的页面做一些输出到客户端之前的处理 方法的原理是:把Response的输出重定向到自定义的容器内,也就是我们的StringBuilder对象里,在HTML所有的向页面输出都变 成了 ...
- c语言-转义序列
字符组合是由反斜杠 (\) 后接字母或位组合构成的字符组合.若要显示换行符,单引号或某些其他字符在字符串末尾,必须使用转义序列. 转义序列被视为单个字符,因此,它是有效的字符常数. 转义序列通常用于指 ...
- Android测试日志文件抓取与分析
1.log文件分类简介 实时打印的主要有:logcat main,logcat radio,logcat events,tcpdump,还有高通平台的还会有QXDM日志 状态信息的有:adb shel ...
- C# var 隐式类型 var 用法 特点
var 关键字是C# 3.0 开始,在方法范围中声明的变量: var有以下特点: * 1.var在编译器编译的时候根据初始值推断出其的类型 * 2.不能赋值除了初始值类型之外的其他类 ...
- hdu_5690_All X(找循环节)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5690 题意: Problem Description F(x, m)F(x,m) 代表一个全是由数字x ...
- %02d
%d表示打印整型的,%2d表示把整型数据打印最低两位,%02d表示把整型数据打印最低两位,如果不足两位,用0补齐所以打印出来就是02了