【C#】并行编程实战:使用 PLINQ(1)

        PLINQ 是语言集成查询(Language Integrate Query , LINQ)的并行实现(P 表示并行)。本章将介绍其编程的各个方面以及与之相关的一些优缺点。

PLINQ 介绍 | Microsoft Learn了解如何使用 .NET 中的 PLINQ 并行执行查询。 PLINQ 代表并行语言集成查询 (LINQ)。icon-default.png?t=N5K3https://learn.microsoft.com/zh-cn/dotnet/standard/parallel-programming/introduction-to-plinq          本教程对应学习工程:魔术师Dix / HandsOnParallelProgramming · GitCode        


1、PLINQ 查询

        在 System.Linq 命名空间和 System.Core 程序集中可以使用 ParallelEnumerable 类。除了支持 LINQ 定义的大多数标准查询运算符(Query Operator)之外,ParallelEnumerable 类还包含许多支持并行执行的方法:

  • AsParallel:这是并行所需的种子方法。

  • AsSequential:通过更改并行行为来启动并行查询的顺序执行。

  • AsOrdered:默认情况下,PLINQ 不保留执行任务和返回结果的顺序。可以通过调用 AsOrdered 方法来保留此顺序。

  • AsUnordered:这是 ParallelQuery 的默认行为,可以被 AsOrdered 方法覆盖。通过调用此方法,可以将行为从有序更改为无序。

  • ForAll:使查询执行可以并行执行。

  • Aggregate:此方法可用于聚合并行查询中各种线程局部分区的结果。

  • WithDegreeOfParallelism:使用此方法时,可以指定用于并行查询执行的处理器的最大数量。

  • WithExecutionMode:使用此方法可以强制并行执行查询,或者让 PLINQ 决定是否需要按顺序或并行执行查询。

         扩展阅读:

详解c# 并行计算_C#教程_脚本之家本文主要介绍了并行计算的简单使用,并行循环的中断和跳出、并行循环中为数组/集合添加项、返回集合运算结果/含有局部变量的并行循环、、PLinq(Linq的并行计算)等相关内容。icon-default.png?t=N5K3https://www.jb51.net/article/202397.htmLINQPad - The .NET Programmer's Playgroundicon-default.png?t=N5K3https://www.linqpad.net/

2、PLINQ 查询简单示例

2.1、并行查询

        这里主要是为了演示并行查询,因此逻辑很简单,就是给定一个数,从列表中找是否有这个数:

        private void SearchNumberParallel()
        {
            //首先获取一个 0~10000的顺序列表:
            var L = Utils.GetOrderList(10000);
            //获取输入查询的目标值
            int targetNumber = commonPanel.GetInt32Parameter();
            //之后开始查询
            int i = 0;
            L.AsParallel().ForAll(x =>
            {
                if (targetNumber == x)
                {
                    Debug.Log($"已经查到:{x},在第{i} 次查询中找到!");
                }
                i++;
            });
            Debug.Log("查询完成");
        }

        如果我们是顺序遍历,那么显然我们输入什么参数,就应该是第几次查到:输入0就是第0次查到,输入999就是在第999次查到。我们运行上述代码,输入1024:

         显然这个顺序就变了,并不是 1024 次。

2.2、顺序查询

        那如果我们要保持查询顺序怎么办呢?只需要稍作修改API即可:

            L.AsParallel().AsSequential().All(x =>
            {
                if (targetNumber == x)
                {
                    Debug.Log($"已经查到:{x},在第{i} 次查询中找到!");
                    return false;//跳出循环
                }
                i++;
                return true;//继续循环
            });

        这样查询结果就如下所示了:

         这里只是 PLINQ 查询语句的简单示例。

3、在并行执行时保持顺序

        PLINQ 将按并行方式执行工作项,在默认情况下,它并不关心保留项目顺序以提高并行查询性能。但是,有时源集合项目中执行顺序很重要,此时需要保持顺序。

        在并行执行项目时保留顺序对性能有直接影响。因为我们需要在分区中保留原始顺序,并确保合并项目时顺序保持一致。

3.1、使用 AsOrdered 方法

        按照书上写的示例,代码如下:

        private void SearchNumberAsOrdered()
        {
            //首先获取一个 0~10000的顺序列表:
            var L = Utils.GetOrderList(10);
            //之后开始查询
            var orderd = L.AsParallel().AsOrdered().Select(x =>
            {
                Debug.LogWarning($"Select : {x}");
                return x;
            }).ToList();

            string foreachStr = "ForEachOrder : ";
            orderd.ForEach(x =>
            {
                foreachStr = $"{foreachStr} - {x}";
            });
            Debug.Log(foreachStr);
        }

        这个代码当然是顺序的…… 因为 orderd 的类型就是 List<T>。打印结果如下:

         如果我们把 AsOrdered 去掉呢?实际上结果也是一样的:

         说实话我不知道他这个 AsOrderd 生效在什么地方……

如何:在 PLINQ 查询中控制排序 | Microsoft Learn详细了解:如何:在 PLINQ 查询中控制排序icon-default.png?t=N5K3https://learn.microsoft.com/zh-cn/dotnet/standard/parallel-programming/how-to-control-ordering-in-a-plinq-query        后来我发现问题所在了,那就是取值的列表,我是自己生成的一个 List<int> ,而示例(无论是书上的还是微软官方网站)一直用的是 Enumerable.Range 生成的迭代器,我换成 Enumerable.Range(0,10) 一下子就和书上对上了。等于说是 List<T>本身对多线程有处理,就是顺序、线程安全的?

List表示可通过索引访问的对象的强类型列表。 提供用于对列表进行搜索、排序和操作的方法。 icon-default.png?t=N5K3https://learn.microsoft.com/zh-cn/dotnet/api/system.collections.generic.list-1?view=netstandard-2.1#thread-safety        翻了下官方文档,好像确实是……

3.2、使用 AsUnOrdered 方法

        一旦在 PLINQ 上使用了 AsOrderd,查询就会按顺序执行。但是一直顺序执行会损失性能,因此我们希望在顺序工作完成之后,改为无序查询以提高性能。

        示例代码如下:

//首先获取一个 0~10的顺序列表:
var L = Enumerable.Range(0, 10);
orderd= L.AsParallel().AsOrdered().Take(5).AsUnordered().Select(x => x * x).ToList();

        这个操作就是取前5项元素,这一步是顺序的,然后再无序返回运算结果。执行结果就是 0~4 各自的平方无序返回为一个 List 。


(未完待续)

本文只是简单介绍了一下 PLINQ 语句的一些基本使用。

本教程对应学习工程:魔术师Dix / HandsOnParallelProgramming · GitCode        

猜你喜欢

转载自blog.csdn.net/cyf649669121/article/details/131551821