并行Linq

news/2024/10/23 9:29:25/
  • 并行LINQ
  1. 并行查询

.NET4在System.Linq名称空间中包含一个新类ParalleIEnumerable ,可以分解查询的工作使其分布在多个线程上。尽管Enmerable类给IEnunerable<T>接口定义了扩展方法,但

ParalleIEnumerable 类的大多数扩展方法是ParallelQuery<TSource>类的扩展。一个重要的例外是AsParallel()方法,它扩展了IEnumerable<TSource>接口,返回ParallelQuery<TSource>类,所以正常的集合类可以以平行方式查询。

例:

    const int arraySize = 100000000;

            var data = new int[arraySize];

            var r = new Random();

            for (int i = 0; i < arraySize; i++)

            {

                data[i] = r.Next(40);

            }

    现在可以使用LINQ查询筛选数据,获取筛选数据的总和。该查询用where子句定义了一个筛选器,仅会中对应值小于20的项,接着调用聚合函数Sum()方法 。与前面的LINQ查询的唯一区别是,这次调用了AsParallel()方法。

    var sum = (from x in data.AsParallel()

                                   where x < 20

                                   select x).Sum();

与前面的LINQ查询一样,编译器会修改语法,以调用AsParallel()、Where()、Select()和Sum()方法。AsParallel()方法用ParallelEnumerable类定义,以扩展IEnumerable<T>接口,所以对简单的数据调用它。AsParallel()方法返回ParallelQuery<TSource>。因为返回的类型,所以编译器选择的Where()方法是ParallelEnumerable.Where(),而不是Enumerable.Where()。在下面的代码中Select()和Sum()方法也来自ParallelEnumerable类。与Enumerable类的实现代码相反,对于ParallelEnumerable类,查询是分区的,以便多个线程可以同时处理该查询。数组可以分为多个部分,其中每个部分由不同的线程处理,以筛选其余项。完成分区的工作后,就需要合并,获得所有部分的总和。

        var sum=data.AsParallel().Where(x=>x<20).Select(x=>x).Sum();

    运行这行代码就会启动任务管理器,这样就可以看出系统的所有CPU都在忙碌。如果删除AsParallel()方法,就不可能使用多个CPU。当然,如果系统上没有多个CPU,就不会看到并行版本带来改进。

  1. 分区器

AsParallel()方法不仅扩展了IEnumerable<T>接口,还扩展了Partition类。通过它,可以影响要创建的分区。

    Partitioner类用System.Collection.Concurrent命名空间定义,并且有不同变体。Create方法接受实现了IList<T>类的数组或对象。根据这一点,以及类型的参数loadBalance和该方法的一些重载版本,会返回一个不同的Partitioner类型。对于数组,.Net4包含派生自抽象基类OrderablePartitioner<TSource>的DynamicPartitionerForArray<TSource>类和StaticPartitionerForArray<TSource>类。

var q1 = (from x in Partitioner.Create(data).AsParallel()

                      where x < 20

                     select x).Sum();

 也可以调用WithExecutionMode()和WithDegreeOfParallelism()方法可以传递ParallelExecutionMode的一个Default值或者ForceParallelism值。默认情况下,并行LINQ避免使用系统开销很高的并行机制。对于WithDegreeOfParallelism()方法,可以传递一个整数值,以指定并行运行的最大任务数。

例:

  const int arraySize = 100000000;

            var data = new int[arraySize];

            var r = new Random();

            for (int i = 0; i < arraySize; i++)

            {

                data[i] = r.Next(40);

            }

            Stopwatch watch = new Stopwatch();

            watch.Start();

            //一种写法,没有添加动态负载均衡,执行完所需要的时间1300毫秒

            var q1 = (from x in Partitioner.Create(data).AsParallel()

                      where x < 80

                     select x).Sum();

        //第二种写法,添加了动态负载均衡,执行完所需要的时间为660毫秒。

var q1 = (from x in Partitioner.Create(data,true).AsParallel()

                      where x < 80

                     select x).Sum();

            watch.Stop();

            Console.WriteLine(watch.ElapsedMilliseconds.ToString());

  1. 取消

.Net提供了一种标准方式,来取消长时间运行的任务,这也适用于并行LINQ。要取消长时间的查询,可以给查询添加WithCancellation()方法,并传递一个CancellationToken令牌作为参数。CancellationToken令牌从CancellationTokenSource类中创建。该查询在单独的线程中运行,在该线程中,捕获一个OperationCancelException类型的异常。如果取消了查询,就触发这个异常。在主线程中,调用CancellationTokenSource类的Cancel()方法可以取消任务。

  const int arraySize = 100000000;

            var data = new int[arraySize];

            var r = new Random();

            for (int i = 0; i < arraySize; i++)

            {

                data[i] = r.Next(40);

            }

            var cts = new CancellationTokenSource();

            new Thread(() =>

                {

                    try

                    {

                        var sum = (from x in data.AsParallel().WithCancellation(cts.Token)

                                   where x < 80

                                   select x).Sum();

                        Console.WriteLine("query finished, sum: {0}", sum);

                    }

                    catch (OperationCanceledException ex)

                    {

                        Console.WriteLine(ex.Message);

                    }

                }).Start();

            Console.WriteLine("query started");

            Console.Write("cancel? ");

            int input = Console.Read();

            if (input == 'Y' || input == 'y')

            {

                // cancel!

                cts.Cancel();

               }

 


http://www.ppmy.cn/news/470553.html

相关文章

L1、L2的作用

L范式都是为了防止模型过拟合&#xff0c;所谓范式就是加入参数的约束。 L1的作用是为了矩阵稀疏化。假设的是模型的参数取值满足拉普拉斯分布。 L2的作用是为了使模型更平滑&#xff0c;得到更好的泛化能力。假设的是参数是满足高斯分布。 借用公众号python与算法社区的内容20…

PLSQL(二)

PLSQL(二&#xff09; 通过本文将学习到 NULL的判断IF控制语句循环控制语句定义复杂类型游标的处理例外的声明函数与存储过程的使用PLSQL中程序包的作用 2、NULL的判断 我一直以为NULL读nang&#xff0c;因为从我开始学计算机的时候别人就这么读。但是我昨天听到有人读no&a…

LDPC概率译码原理实例说明

1.1译码公式理解 译码公式的证明很多书籍里边已有介绍&#xff0c;这里不做证明直接引用。介绍Gallager概率译码公式之前先介绍引理&#xff1a;二进制序列长度为m且相互独立&#xff0c;第i个bit为1的概率为 P i P_{i} Pi​&#xff0c;那么整个序列为偶数个1的概率为&#x…

论文浅尝 | Efficient RDF graph storage based on RL

笔记整理&#xff1a;郑国鹏&#xff0c;天津大学硕士 链接&#xff1a;https://link.springer.com/article/10.1007/s11280-021-00919-x 动机 知识是人工智能的基石&#xff0c;它通常以RDF图的形式表示。各个领域的大规模RDF图对图数据管理提出了新的挑战。关系型数据库因其成…

电偶极子的场

电偶极子是两个分隔一段距离&#xff0c;电量相等&#xff0c;正负相反的电荷。在距离远超于两个点电荷相隔距离之处&#xff0c;物理电偶极子所产生的电场&#xff0c;可以近似为其电偶极矩所产生的电场。令物理电偶极子的两个点电荷相隔距离趋向于 0 &#xff0c;同时保持其电…

PMSM学习(4)——控制方式总结

同步电机主要控制方法&#xff08;含SynRM与PMSM&#xff09; 一、矢量控制 1.最大转矩/电流比控制——MTPA 这是在定子电流最优控制问题在恒转矩控制下提出的控制方法。 已知PMSM转矩方程为 T e p [ Ψ f i q ( L d − L q ) i d i q ] T_ep[\Psi_fi_q(L_d-L_q)i_di_q] T…

L二

接上文&#xff0c;看完了结构体&#xff0c;也也应该知道个大概了&#xff0c;整个驱动部分围绕fb_info来&#xff0c;对其进行填充最后调用frambuffer_register将其注册进内核&#xff0c; 接下来看详细分析&#xff1a; 426 static int mxcfb_ioctl(struct fb_info *fbi, u…

IBM MQ相关总结——命令篇之创建远程队列

由于是本地模拟&#xff0c;用两个队列管理器来实现&#xff0c;一个发消息一个收消息 接收方机器&#xff1a; 1.通过输入以下命令来启动 MQSC&#xff1a; runmqsc TESTMQ2 2.定义名为 TESTMQ2_LQ1 的本地队列&#xff1a; define qlocal(TESTMQ2_LQ1) 3.通过输入以下命令来定…