命令式数据并行

    Visual C# 2010和.NETFramework4.0提供了很多令人激动的新特性,这些特性是为应对多核处理器和多处理器的复杂性设计的。然而,因为他们包括了完整的新的特性,开发人员和架构师必须学习一种新的编程模型。

这一章是一些新的类、结构体和枚举类型,你可以使用这里来处理数据并行的场景。这章将为你展示怎样创建并行代码和描述与每个场景相关的新概念,而不是关注并发编程中的最复杂的问题。这样你将可以更加充分的理解性能改进。

开始并行任务

   使用先前版本的.NET Framework,开发可以充分利用多核微处理器的并行能力的应用程序是很难的。使用那些可以控制并行的复杂结构来开始、控制、管理和同步多线程是必要的,但是这对现代的多核系统并不十分有效。

.NET 4引入了新的任务并行库(TPL),其产生在多核时代并且就是第一章中展示的轻量级并发编程模型。

为了支持数据并行、任务并行和管道,TPL提供了一个轻量级的框架,可以帮助开发人员应对不同的并行场景,实现基于任务模型的设计,而不是使用重量级复杂的线程进行工作。这些场景包括

数据并行

  这里有很多的数据,并且每条数据都必须施加相同的操作。如图2-1,使用256位键的AES算法加密100个unicode字符串。

图 2-1

任务并行

      这里有很多不同的操作可以并行执行,充分的利用并行的有力。例如,产生文件的哈希编码,加密unicode字符串,创建图片的缩略图。如图2-2,

图 2-2

   流水线

   这里混杂了任务并行和数据并行。这是最复杂的场景,因为它总是需要协调多个特定的并发任务。例如,以使用256位键的AES算法加密100个unicode字符串,然后为每个加密的字符串产生一个哈希值。这个管道可以实现同时运行两个并发执行加密和产生哈希代码两个任务。每一个加密的unicode字符串为了使用哈希编码算法进行处理而放入队列中。如图2-3,

图 2-3

  当然也存在混合了前边的所有情况的复杂场景。理解怎样使用并行任务进行工作的最容易的方式就是使用他们。接下来的章节将会使用详细的例子覆盖这些最普遍的场景。

  TPL引入了一个新的命名空间,System.Threading.Tasks。通过这个命名空间可以访问.NET4引入的新的类、结构体、枚举类型。所以,无论什么时候你想用TPL,使用这个命名空间是个不错的主意。

  Using System.Threading.Tasks;

这样你可以避免大量的引用。例如,你可以使用Parallel.Invoke,而不是使用System.Threading.Tasks.Parallel.Invoke.

其中主要的类是Task,它代表一个异步的并发操作。然而,没有必要为了创建并行代码直接使用Task的实例。有时,最好的选择是创建并行的循环和区域。在这些场景中,你可以使用静态类Parallel提供的方法进行工作,而不是使用更底层的Task实例。

  • Parallel.For---为固定数目的独立For循环迭代提供负载均衡的潜在的并行执行。

  • Parallel.ForEach---为固定数目的独立For Each循环迭代提供负载均衡的潜在的并行执行。这种方法支持自定义分区类,这是你可以完全控制数据的分布。

  • Parallel.Invok---对独立的任务提供潜在的并行执行。

负载均衡的执行会尝试将工作分发在不同的任务中,这样所有的任务在大部分的时间内都可以保持繁忙。负载均衡总是试图减少任务的闲置时间。

    当重构已经存在的代码来充分利用潜在的并发优势时,这些方法是很有用的。然而,理解这些并不是使用Parallel.For取代for那样简单是很重要的。

Parallel.Invoke

  如果试图将很多方法并行执行最简单的方法就是使用Parallel提供的Invoke方法。以下是.NET中Parallel的Invoke函数原型。Invoke接受没有返回值(或者说返回值是void)Action[]参数数组,对操作尽可能的并行化。

public static void Invoke(params Action[] actions);

/// <summary>

/// 执行所提供的每个操作,而且尽可能并行运行,除非用户取消了操作。

/// </summary>

  有以下四个函数:

        static void First()

        {

            System.Console.WriteLine("1--First");

        }

        static void Second()

        {

            System.Console.WriteLine("2--Second");

        }

        static void Third()

        {

            System.Console.WriteLine("3--Third");

        }

        static void Fourth()

        {

            System.Console.WriteLine("4--Fourth");

        }  

使用Parallel的Invoke函数,并行执行以上四个函数。

     Parallel.Invoke(

            () => First(),

            () => Second(),

            () => Third(),

            () => Fourth());

  以上调用()=>First()的形式是Lambda表达式。也可以使用匿名委托来执行以上代码,如下代码所示。

     Parallel.Invoke(

                delegate { First(); },

                delegate { Second(); },

                delegate { Third(); },

                delegate { Fourth(); });

  或者直接传入函数参数,如下代码所示,但是使用Lambda表达式和匿名委托的一大优势:可以定义需要并行执行的多行方法,而不需要创建额外的方法。

      Parallel.Invoke(

                First,

                Second,

                Third,

                Fourth);

    输出结果是:

  第一次执行:3-1-2-4

  第二次执行:1-2-3-4

  第三次执行:2-3-4-1

  使用Parallel的Invoke函数时需要特别注意以下量两点:1、函数执行不要求特定的顺序。2、函数执行必须独立的,不存在特定的依赖关系。

  优势和权衡

  使用Parallel.Invoke的关键优势在于,这是运行并行方法的简单方式,而不用考虑任务和线程问题。然而Invoke并不适合所有情形。需要权衡一下几个方面:

  •   如果使用Parallel.Invoke加载的方法运行时间不同,那么就需要很长的时间才能返回控制。这样很多逻辑内核就处于闲置状态。因此,使用时,一定要测量运行的结果、实现的加速比,以及逻辑内核的使用率,这是很重要的。

  •   在并行的可扩展方面具有局限性。因为Parallel.Invoke调用的是固定数目的委托。

  •   每次调用Parallel.Invoke都要产生一些额外开销。

  •   与其他的并行代码一样,不同方法的任何相关性或不可控的交互会导致难以检测的bug以及意想不到的副作用。

  •   对方法的执行顺序没有要求时,可以考虑Parallel.Invoke方法。需要特定执行顺序的复杂算法不适合使用parallel.Invoke

  •   使用parallel.Invoke并行运行方法中,要考虑异常处理问题。

C#并行编程--命令式数据并行(Parallel.Invoke)---与匿名函数一起理解(转载整理)的更多相关文章

  1. C#并行编程--命令式数据并行(Parallel.Invoke)

    命令式数据并行   Visual C# 2010和.NETFramework4.0提供了很多令人激动的新特性,这些特性是为应对多核处理器和多处理器的复杂性设计的.然而,因为他们包括了完整的新的特性,开 ...

  2. C#并行编程之数据并行

    所谓的数据并行的条件是: 1.拥有大量的数据. 2.对数据的逻辑操作都是一致的. 3.数据之间没有顺序依赖. 运行并行编程可以充分的利用现在多核计算机的优势.记录代码如下: public class ...

  3. 并行编程多线程之Parallel

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

  4. 五 浅谈CPU 并行编程和 GPU 并行编程的区别

    前言 CPU 的并行编程技术,也是高性能计算中的热点,也是今后要努力学习的方向.那么它和 GPU 并行编程有何区别呢? 本文将做出详细的对比,分析各自的特点,为将来深入学习 CPU 并行编程技术打下铺 ...

  5. 第五篇:浅谈CPU 并行编程和 GPU 并行编程的区别

    前言 CPU 的并行编程技术,也是高性能计算中的热点,也是今后要努力学习的方向.那么它和 GPU 并行编程有何区别呢? 本文将做出详细的对比,分析各自的特点,为将来深入学习 CPU 并行编程技术打下铺 ...

  6. C#并发编程之初识并行编程

    写在前面 之前微信公众号里有一位叫sara的朋友建议我写一下Parallel的相关内容,因为手中商城的重构工作量较大,一时之间无法抽出时间.近日,这套系统已有阶段性成果,所以准备写一下Parallel ...

  7. 一、并行编程 - 数据并行 System.Threading.Tasks.Parallel 类

    一.并行概念 1.并行编程 在.NET 4中的并行编程是依赖Task Parallel Library(后面简称为TPL) 实现的.在TPL中,最基本的执行单元是task(中文可以理解为"任 ...

  8. 【读书笔记】.Net并行编程高级教程--Parallel

    一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控>这本书中也多次提到并发,不管是计算机 ...

  9. C#并行编程-Parallel

    菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...

随机推荐

  1. Verify Preorder Serialization of a Binary Tree

    One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, ...

  2. linux shell脚本守护进程监控svn服务

    最近搭建的svn服务不知道什么原因服务总是被关闭(如果你不知道怎么搭建svn可以参考linux下搭建svn版本控制软件),因此用shell脚本实现一个守护进程.用于监控svn服务是否启动,如果服务不在 ...

  3. 集群管理 secondaryNameNode和NameNode(转)

    为了达到以下负责均衡,需要调整以下 改变负载 三台机器,改变负载 host2(NameNode.DataNode.TaskTracker) host6(SecondaryNameNode.DataNo ...

  4. 菜鸟学Linux命令:find命令 查找文件

    find命令是Linux下最常用的命令之一,灵活的使用find命令,你会发现查找文件变得十分简单. 命令格式 find [指定查找目录]  [查找规则(选项)]  [查找完后执行的动作] 参数规则 - ...

  5. 3.Factory Method 工厂方法模式(创建型模式)

    1.定义: 定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使得一个类的实例化延迟到子类. 2.实现代码如下: /// <summary> /// 工厂方 ...

  6. 蓝桥杯 算法训练 区间k大数查询(水题)

    算法训练 区间k大数查询 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. ...

  7. Oracle数据库表设计时的注意事项

    表是Oracle数据库中最基本的对象之一.万丈高楼从平地起,这个基础对象对于数据库来说,非常重要.因为其设计是否合理,直接跟数据库的性能相关.从Oracle数据库菜鸟到数据库专家这个过程中,在表设计与 ...

  8. 把一个SVN项目的目录结构 导入到另外一个空白的SVN项目里

    1 选好源目录,选中“check out” 2 选中想要的目录结构 3 选择具体的目录 4 确定,最后开始更新,成功!

  9. 小甲鱼PE详解之区块表(节表)和区块(节)续(PE详解05)

    这一讲我们结合实例来谈谈区块表的定义以及各个属性的含义. 首先,我们先用之前学过的一点知识在二进制文件中手动翻找区块表,这样做的好处是可以使你很快的对PE结构牢记于心.学来的东西就是能用的东西,不能用 ...

  10. eclipse下提交job时报错mapred.JobClient: No job jar file set. User classes may not be found.

    错误信息: 11/10/14 13:52:07 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. A ...