在一些常见的编程情形中,使用任务也许能提升性能。为了简化变成,静态类System.Threading.Tasks.Parallel封装了这些常见的情形,它内部使用Task对象。

Parallel.For & Parallel.Foreach & Pararllel.Invoke 

           Parallel.For(, , (i) =>
{
//i是从0开始一直到1000结束 }); var lst = new List<string>(); Parallel.ForEach(lst, (s) =>
{
//do something
}); //Invoke
Parallel.Invoke(
() => { },
() => { },
() => { }
);

三个不同的方式做并行操作,Invoke是自己定义的并行,像上面的代码,只会开三个线程去做,而For和Foreach和普通的没什么区别只是并行去做了.

这里需要注意的是:这个三个方法都会堵塞当前线程,要等待所有线程都做完了以后才能往下执行,这是有用的,当进行数据分析的时候,每条数据都是独立的,这个时候等待所有线程做完是有意义的,而如果需要不堵塞线程可以用TASK来包一层,具体请参照【C#】线程之Task。在并发的时候如果有某些线程出现了异常,这个时候不会中断线程,会在所有线程结束的时候抛出AggregateException(并不是所有异常都能用这个捕获),我们通过这个异常可以知道所有的异常:

           Parallel.ForEach(new List<string>
{
"aa",
"bb",
"cc",
"dd",
"ee",
}, (b) =>
{
Thread.Sleep();
throw new Exception(b);
});
}
catch (AggregateException ex)
{
foreach (var exception in ex.Flatten().InnerExceptions)
{
Console.WriteLine(exception.Message);
} }

ParallelOptions

看一下官方给出的解释:

  

    public class ParallelOptions
{ public ParallelOptions(); //允许取消操作
public CancellationToken CancellationToken { get; set; } //允许指定可以并发操作的最大工作项目数
public int MaxDegreeOfParallelism { get; set; } //允许指定要使用哪个TaskScheduler
public TaskScheduler TaskScheduler { get; set; }
}

这个类提供我们最大并发数量的设置,取消操作的Token赋值,以及任务调度器的设置(关于这个,需要另拉一章来说,此处只关注前面两个)

        //定义线程取消的一个对象
var cancel = new CancellationTokenSource(); var po = new ParallelOptions()
{
CancellationToken = cancel.Token,
MaxDegreeOfParallelism = 2,
};
//为了不堵塞线程,这里开启一个线程
Task.Run(() =>
{
try
{
Parallel.For(0, 1000, po, (i) =>
{
Thread.Sleep(1000);
po.CancellationToken.ThrowIfCancellationRequested();
Console.WriteLine(i);
});
}
catch (AggregateException ex)
{ foreach (var e in ex.Flatten().InnerExceptions)
{
Console.WriteLine(e.Message);
}
}
catch (Exception ex)
{
//OperationCanceledException
Console.WriteLine(ex.GetType().Name);
}
//不设置取消的TOKEN
}, CancellationToken.None); Thread.Sleep(10 * 1000);
cancel.Cancel();

线程最大并行数位2个,如果取消的话,整个Parallel会全部取消,并且抛出OperationCanceledException异常。

Parallel.For & Parallel.Foreach的重载

  我只挑选了一个重载来说

public static ParallelLoopResult For<TLocal>
  (int fromInclusive, int toExclusive,
   Func<TLocal> localInit,
   Func<int, ParallelLoopState, TLocal, TLocal> body,
Action<TLocal> localFinally);

  

来看一下官方的解释:

   localInit:任务局部初始化,为参与工作的每一个任务都调用一次该委托这个委托在任务被要求处理一个工作项之前调用的。

   boy:为参与工作的各个线程锁处理的每一项都调用一次该委托

localFinally:任务局部终结委托,为参与工作的每一个任务都调用一次该委托,这个委托是在任务处理好派给它的所有工作项之后调用的。即使主体委托代码引发一个未处理的异常,也会调用它。

    

public static void Parallel_For_Local_Test()

{
int[] nums = Enumerable.Range(, ).ToArray<int>(); long total = ; ParallelLoopResult result = Parallel.For<long>(, nums.Length,
() => { return ; },
(j, loop, subtotal) =>
{
// 延长任务时间,更方便观察下面得出的结论 Thread.SpinWait(); Console.WriteLine("当前线程ID为:{0},j为{1},subtotal为:{2}。" , Thread.CurrentThread.ManagedThreadId, j.ToString(), subtotal.ToString()); if (j == ) loop.Break(); if (j > loop.LowestBreakIteration)
{
Thread.Sleep();
Console.WriteLine("j为{0},等待4s种,用于判断已开启且大于阻断迭代是否会运行完。", j.ToString());
}
Console.WriteLine("j为{0},LowestBreakIteration为:{1}", j.ToString(), loop.LowestBreakIteration);
subtotal += nums[j];
return subtotal;
},
(finalResult) => Interlocked.Add(ref total, finalResult)
); Console.WriteLine("total值为:{0}", total.ToString());
if (result.IsCompleted)
Console.WriteLine("循环执行完毕");
else
Console.WriteLine("{0}"
, result.LowestBreakIteration.HasValue ? "调用了Break()阻断循环." : "调用了Stop()终止循环."); }

  看一下输出

分析一下:

a)        泛型类型参数TLocal为本地线程数据类型,本示例设置为long。

b)        三个委托的参数解析body(j, loop, subtotal):首先初始委托localInit中返回了0,所以body委托中参数subtotal的初始值即为0,body委托的参数j对应的是当前迭代索引,参数loop为当前迭代状态ParallelLoopState对象;localFinally委托参数为body委托的返回值。

c)        三个委托三个阶段中都可能并行运行,因此您必须同步对任何共享变量的访问,如示例中在finally委托中使用了System.Threading.Interlocked对象。

d)        在索引为23的迭代中调用Break()后:

i.              索引小于23的所有迭代仍会运行(即使还未开始处理),并在退出循环之前处理完。

ii.              索引大于 23 的迭代若还未开启则会被放弃;若已处于运行中则会在退出循环之前处理完。

e)        对于调用Break()之后,在任何循环迭代中访问LowestBreakIteration属性都会返回调用Break()的迭代对应的索引。

                                                                注:滴答的雨(何雨泉)的帮助

ParallelLoopState

    可用来使 Tasks.Parallel 循环的迭代与其他迭代交互,并为 Parallel 类的循环提供提前退出循环的功能。此类的实例不要自行创建,它由 Parallel 类创建并提供给每个循环项,并且只应该在提供此实例的“循环内部”使用。

  

public class ParallelLoopState

{

    // 获取循环的任何迭代是否已引发相应迭代未处理的异常。
public bool IsExceptional { get; } // 获取循环的任何迭代是否已调用 ParallelLoopState.Stop()。
public bool IsStopped { get; } // 获取在Parallel循环中调用 ParallelLoopState.Break() 的最低循环迭代。
public long? LowestBreakIteration { get; } // 获取循环的当前迭代是否应基于此迭代或其他迭代发出的请求退出。
public bool ShouldExitCurrentIteration { get; } //通知Parallel循环当前迭代”之后”的其他迭代不需要运行。
public void Break(); //通知Parallel循环当前迭代“之外”的所有其他迭代不需要运行。
public void Stop();
}

  

Break()

Break()用于通知Parallel循环当前迭代“之后”的其他迭代不需要运行。例如,对于从 0 到 1000 并行迭代的 for 循环,如果在第 100 次迭代调用 Break(),则低于 100 的所有迭代仍会运行(即使还未开始处理),并在退出循环之前处理完。从 101 到 1000 中还未开启的迭代则会被放弃。

对于已经在执行的长时间运行迭代,Break()将为已运行还未结束的迭代对应ParallelLoopResult结构的LowestBreakIteration属性设置为调用Bread()迭代项的索引。

Stop()

Stop() 用于通知Parallel循环当前迭代“之外”的所有其他迭代不需要运行,无论它们是位于当前迭代的上方还是下方。

对于已经在执行的长时间运行迭代,可以检查 IsStopped属性,在观测到是 true 时提前退出。

Stop 通常在基于搜索的算法中使用,在找到一个结果之后就不需要执行其他任何迭代。(比如在看视频或漫画时自动匹配响应最快的服务器)

ShouldExitCurrentIteration 属性

当循环的迭代调用 Break 或 Stop时,或一个迭代引发异常,或取消循环时,Parallel 类将主动尝试禁止开始执行循环的其他迭代。但是,可能有无法阻止其他迭代启动的情况。也可能是长时间运行的迭代已经开始执行的情况。在此类情况下,迭代可以通过显式检查 ShouldExitCurrentIteration 属性,在该属性返回 true 时停止执行。

  

   LowestBreakIteration 属性

  返回过程中调用过Break方法的最低的项,如果从来没有调用过Break则返回null.

 

这里还有一个好玩的地方, 我们知道Parallel.For & Parallel.Foreach会返回一个ParallelLoopResult类型的对象,我们可以通过IsComplete()来判断是否结束并发,但是如果我们用了ParallelLoopState的Break(), 这个时候IsComplete()返回的是false,并且LowestBreakIteration属性不为null,如果调用的是Stop(), IsComplete()返回的是true,且LowestBreakIteration属性为null.

【C#】线程之Parallel的更多相关文章

  1. 并行编程多线程之Parallel

    1.简介 随着多核时代的到来,并行开发越来越展示出它的强大威力!使用并行程序,充分的利用系统资源,提高程序的性能.在.net 4.0中,微软给我们提供了一个新的命名空间:System.Threadin ...

  2. C#多线程之Parallel中 类似于for的continue,break的方法

    好久没写东西了,终于找到点知识记录下... 利用ParallelLoopState对象来控制Parallel.For函数的执行,ParallelLoopState对象是由运行时在后台创建的: Para ...

  3. 多线程之Parallel类

    Parallel类是对线程的一个抽象.该类位于System.Threading.Tasks名称空间中,提供了数据和任务并行性. Paraller类定义了数据并行地For和ForEach的静态方法,以及 ...

  4. iOS多线程之8.NSOPeration的其他用法

      本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...

  5. python 线程之 threading(四)

    python 线程之 threading(三) http://www.cnblogs.com/someoneHan/p/6213100.html中对Event做了简单的介绍. 但是如果线程打算一遍一遍 ...

  6. python 线程之 threading(三)

    python 线程之 threading(一)http://www.cnblogs.com/someoneHan/p/6204640.html python 线程之 threading(二)http: ...

  7. python 线程之_thread

    python 线程之_thread _thread module: 基本用法: def child(tid): print("hello from child",tid) _thr ...

  8. Java多线程之ConcurrentSkipListMap深入分析(转)

    Java多线程之ConcurrentSkipListMap深入分析   一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下, ...

  9. iOS多线程之GCD小记

    iOS多线程之GCD小记 iOS多线程方案简介 从各种资料中了解到,iOS中目前有4套多线程的方案,分别是下列4中: 1.Pthreads 这是一套可以在很多操作系统上通用的多线程API,是基于C语言 ...

随机推荐

  1. 英語版Windows Server 2012 R2を日本語化する手順

    [スタート]ボタンを押し.[Control Panel]を起動 [Clock, Language and Region]の下の[Add a Language]をクリック [Add a Language ...

  2. iOS:缓存与Operation优先级问题

    这篇博客来源于今年的一个面试题,当我们使用SDWebImgae框架中的sd_setImageWithURL: placeholderImage:方法在tableView或者collectionView ...

  3. pecl install imagick

    steven@server:/var/www$ sudo pecl install imagickdownloading imagick-2.3.0.tgz ...Starting to downlo ...

  4. 标准 DateTime 格式字符串

    标准 DateTime 格式字符串 MSDN 标准 DateTime 格式字符串包含一个标准 DateTime 格式说明符字符,该字符表示自定义 DateTime 格式字符串.格式字符串最终定义由格式 ...

  5. IBM HTTP Server Performance Tuning

    IBM HTTP Server Performance Tuninghttp://publib.boulder.ibm.com/httpserv/ihsdiag/ihs_performance.htm ...

  6. 【经验谈】XmlSerializer的坑

    XmlSerializer我想现在用的人可能不多了,大家都在用Json.我现在所在的公司依然在用,所以发现了这个坑.当然这个坑存在很久了只是没用过所以才发现. 事情是这样的,测试那边说系统偶尔会报找不 ...

  7. Web功能之组织结构图

    前提:由于项目需要显示组织结构图的形式 工具:VS2010 项目:ASP.NET 自带的web项目 (带模板页) 插件:OrgChart(依赖:OrgChart.dll).JOrgChart 不多说 ...

  8. [翻译]使用Swift在Xcode中创建自定义控件

    使用Swift在Xcode中创建自定义控件 原文 IBDesignable and IBInspectable With IBDesignable and IBInspectable, develop ...

  9. hybrid开发设计

    hybrid方案背景 大部分业务都是在不停改变的,我们希望native不发布新版本就可以让线上用户使用新功能.我们要实现这样的方式,采用h5来实现就可以满足这一要求,准确说是native里提供一个装载 ...

  10. NGUI Atlas

    打开 Atlas Maker:NGUI -> Open -> Atlas Maker 新建一个 "Icon Atlas" 生成3个东西: