欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c#中LINQ的基本用法(三)

 更新時(shí)間:2022年04月12日 17:02:16   作者:Ruby_Lu  
這篇文章介紹了c#中LINQ的基本用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下的相關(guān)資料

一.并行LINQ

System.Linq名稱(chēng)空間中包含的類(lèi)ParallelEnumerable可以分解查詢(xún)的工作,使其分布在多個(gè)線(xiàn)程上。
盡管Enumerable類(lèi)給IEnumerable<T>接口定義了擴(kuò)展方法,但ParallelEnumerable類(lèi)的大多數(shù)擴(kuò)展方法是ParallerQuery<TSource>類(lèi)的擴(kuò)展。例如,AsParallel()方法,它擴(kuò)展了IEnumerable<T>接口,返回ParallelQuery<T>類(lèi),所以正常的集合類(lèi)可以以平行方式查詢(xún)。

1.并行查詢(xún)

下面演示并行LINQ(Parallel LINQ,PLINQ):

//用隨機(jī)值填充一個(gè)大型的int集合
        // Enumerable.Range(0, arraySize),生成指定范圍內(nèi)的整數(shù)的空序列。
        //Select(x => r.Next(140)),用小于140的數(shù)填充集合
        static IEnumerable<int> SampleData()
        {
          const int arraySize = 100000000;
          var r = new Random();
          return Enumerable.Range(0, arraySize).Select(x => r.Next(140)).ToList();
        }

        static void IntroParallel()
        {
          var data = SampleData();

          var watch = new Stopwatch();

        //非并行LINQ
          watch.Start();
          var q1 = (from x in data
                    where Math.Log(x) < 4
                    select x).Average();
          watch.Stop();
          Console.WriteLine("sync {0}, result: {1}", watch.ElapsedMilliseconds, q1);

          watch.Reset();
          
          //使用data.AsParallel()進(jìn)行并行LINQ
          watch.Start();
          var q2 = (from x in data.AsParallel()
                where Math.Log(x) < 4
                select x).Average();
          watch.Stop();
          Console.WriteLine("async {0}, result: {1}", watch.ElapsedMilliseconds, q2);
        }

輸出;

發(fā)現(xiàn)并行查詢(xún)時(shí)間用的少,在并行查詢(xún)時(shí)CPU利用率達(dá)到100%
與LINQ基礎(chǔ)(二)(http://www.dbjr.com.cn/article/244215.htm)中的LINQ查詢(xún)一樣,編譯器會(huì)修改語(yǔ)法,以調(diào)用AsParallel,Where(),Select(),Average()方法:

  var q2 = data.AsParallel().Where(x => Math.Log(x)<4).Select(x => x).Average();

AsParallel()方法用ParallerEnumerable類(lèi)定義,以擴(kuò)展IEnumerable<T>接口,所以可以對(duì)簡(jiǎn)單的數(shù)組調(diào)用它。AsParallel()方法返回ParallerQuery<T>。因?yàn)榉祷氐念?lèi)型,所以編譯器選擇的Where()方法是ParallerEnumerable.Where(),而不是Enumerable.Where()。
對(duì)于PrarllelEnumerable類(lèi),查詢(xún)是分區(qū)的,以便多個(gè)線(xiàn)程可以同時(shí)處理該查詢(xún)。集合可以分為多個(gè)部分,其中每個(gè)部分由不同的線(xiàn)程處理。完成分區(qū)的工作后,就需要合并,獲得所有部分的總和。

2.分區(qū)器

AsParallel()方法不僅擴(kuò)展了IEnumerable<T>接口,還擴(kuò)展了Partitioner類(lèi)。通過(guò)它可以影響要?jiǎng)?chuàng)建的分區(qū)。
Partitioner類(lèi)用System,Collection.Concurrent名稱(chēng)空間定義,并且有不同的變體。Create()方法接受實(shí)現(xiàn)了IList<T>類(lèi)的數(shù)組或?qū)ο?,以及Boolean類(lèi)型的參數(shù),返回一個(gè)不同的Partitioner類(lèi)型。Create()方法有多個(gè)重載版本。

    var q2 = (from x in Partitioner.Create(data).AsParallel()
      where Math.Log(x) < 4
        select x).Average();

也可以對(duì)AsParallel()方法接著調(diào)用WithExecutionMode()和WithDegreeOfParallelism()方法,來(lái)影響并行機(jī)制。WithExecutionMode()方法可以傳遞ParallelExecutionMode的一個(gè)Default值或者ForceParallelism值。默認(rèn)情況下,并行LINQ避免使用系統(tǒng)開(kāi)銷(xiāo)很高的并行機(jī)制。WithDegreeOfParallelism()方法,可以傳遞一個(gè)整數(shù)值,以指定應(yīng)并行運(yùn)行的最大任務(wù)數(shù)。如果查詢(xún)不應(yīng)使用全部CPU,這個(gè)方法很有用。

3.取消

要取消長(zhǎng)時(shí)間運(yùn)行的查詢(xún),可以給查詢(xún)添加WithCancellation()方法,并傳遞一個(gè)CancellationToken令牌作為參數(shù)。CancellationToken令牌從CancellationTokenSource類(lèi)中創(chuàng)建。
舉個(gè)例子,下面的查詢(xún)?cè)趩为?dú)的線(xiàn)程中運(yùn)行,如果取消了查詢(xún),在該線(xiàn)程中捕獲一個(gè)OperationCanceledException類(lèi)型的異常。在主線(xiàn)程中,可以調(diào)用CancellationTokenSource類(lèi)的Cancle()方法取消任務(wù)。

var data = SampleData();
          var watch = new Stopwatch();

          watch.Start();
          Console.WriteLine("filled array");
          var sum1 = (from x in data
                      where Math.Log(x) < 4
                      select x).Average();
          Console.WriteLine("sync result {0}", sum1);

          var cts = new CancellationTokenSource();
          
          Task.Factory.StartNew(() =>
            {
              try
              {
                var res = (from x in data.AsParallel().WithCancellation(cts.Token)
                           where Math.Log(x) < 4
                           select x).Average();
                Console.WriteLine("query finished, result: {0}", res);
              }
              catch (OperationCanceledException ex)
              {
                Console.WriteLine(ex.Message);
              }
            });
          watch.Stop();
          Console.WriteLine("async {0}, result: {1}", watch.ElapsedMilliseconds, "res");
          Console.WriteLine("query started");
          Console.Write("cancel? ");
          string input = Console.ReadLine();
          if (input.ToLower().Equals("y"))
          {
              cts.Cancel();
              Console.WriteLine("sent a cancel");
          }

          Console.WriteLine("press return to exit");
          Console.ReadLine();

二.表達(dá)式樹(shù)

在LINQ To Object 中,擴(kuò)展方法需要將一個(gè)委托類(lèi)型作為參數(shù),這樣就可以將lambda表達(dá)式賦予參數(shù)。lambda表達(dá)式也可以賦予Expression<T>類(lèi)型的參數(shù),C#編譯器根據(jù)類(lèi)型給lambda表達(dá)式定義不同的行為。如果類(lèi)型是Expression<T>,編譯器就從lambda表達(dá)式中創(chuàng)建一個(gè)表達(dá)式樹(shù),并存儲(chǔ)在程序集中。這樣就可以在運(yùn)行期間分析表達(dá)式樹(shù),并進(jìn)行優(yōu)化,以便查詢(xún)數(shù)據(jù)源。

  var racers = from r in Formula1.GetChampions()
    where r.Wins > 15 && (r.Country == "Brazil" || r.Country == "Austria")
      select r;

這個(gè)查詢(xún)表達(dá)式使用了擴(kuò)展方法Where(),Select()方法。Enumerable類(lèi)定義了Where()方法,并將委托類(lèi)型Func<T,bool>作為參數(shù)謂詞:

  public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,Func<TSource,bool> predicate);

這樣,就可以把lambda表達(dá)式賦予委托predicate。
除了使用委托之外,編譯器還會(huì)把表達(dá)式樹(shù)放在程序集中。表達(dá)式樹(shù)可以在運(yùn)行期間讀取。表達(dá)式樹(shù)從派生自抽象基類(lèi)Expression的類(lèi)中構(gòu)建。Expression和Expression<T>不同。繼承自Expression類(lèi)的表達(dá)式類(lèi)有BinaryExpression,ConstantExpression,InvocationExpression等。編譯器會(huì)從lambda表達(dá)式中創(chuàng)建表達(dá)式樹(shù)。
例如,lambda表達(dá)式r.Country == "Brazil"使用了ParameterExpression,MemberExpression,ConstantExpression,MethodCallExpression,來(lái)創(chuàng)建一個(gè)表達(dá)式樹(shù),并將該樹(shù)存儲(chǔ)在程序集中,之后在運(yùn)行期間使用這個(gè)樹(shù),創(chuàng)建一個(gè)用于底層數(shù)據(jù)源的優(yōu)化查詢(xún):

//DisplayTree方法在控制臺(tái)上圖形化的顯示表達(dá)式樹(shù)。其中傳遞一個(gè)Expression對(duì)象,并根據(jù)表達(dá)式的類(lèi)型,把表達(dá)式的一些信息寫(xiě)到控制臺(tái)上
                private static void DisplayTree(int indent, string message, Expression expression)
                {
                    string output = String.Format("{0} {1} ! NodeType: {2}; Expr: {3} ",
                          "".PadLeft(indent, '>'), message, expression.NodeType, expression);

                    indent++;
                    switch (expression.NodeType)
                    {
                        case ExpressionType.Lambda:
                            Console.WriteLine(output);
                            LambdaExpression lambdaExpr = (LambdaExpression)expression;
                            foreach (var parameter in lambdaExpr.Parameters)
                            {
                                DisplayTree(indent, "Parameter", parameter);
                            }
                            DisplayTree(indent, "Body", lambdaExpr.Body);
                            break;
                        case ExpressionType.Constant:
                            ConstantExpression constExpr = (ConstantExpression)expression;
                            Console.WriteLine("{0} Const Value: {1}", output, constExpr.Value);
                            break;
                        case ExpressionType.Parameter:
                            ParameterExpression paramExpr = (ParameterExpression)expression;
                            Console.WriteLine("{0} Param Type: {1}", output, paramExpr.Type.Name);
                            break;
                        case ExpressionType.Equal:
                        case ExpressionType.AndAlso:
                        case ExpressionType.GreaterThan:
                            BinaryExpression binExpr = (BinaryExpression)expression;
                            if (binExpr.Method != null)
                            {
                                Console.WriteLine("{0} Method: {1}", output, binExpr.Method.Name);
                            }
                            else
                            {
                                Console.WriteLine(output);
                            }
                            DisplayTree(indent, "Left", binExpr.Left);
                            DisplayTree(indent, "Right", binExpr.Right);
                            break;
                        case ExpressionType.MemberAccess:
                            MemberExpression memberExpr = (MemberExpression)expression;
                            Console.WriteLine("{0} Member Name: {1}, Type: {2}", output,
                               memberExpr.Member.Name, memberExpr.Type.Name);
                            DisplayTree(indent, "Member Expr", memberExpr.Expression);
                            break;
                        default:
                            Console.WriteLine();
                            Console.WriteLine("{0} {1}", expression.NodeType, expression.Type.Name);
                            break;
                    }
                }


                static void Main()
                {
                    Expression<Func<Racer, bool>> expression = r => r.Country == "Brazil" && r.Wins > 6;

                    DisplayTree(0, "Lambda", expression);

                }

輸出:

使用Expression<T>類(lèi)型的一個(gè)例子是ADO.NET EF 和WCF數(shù)據(jù)服務(wù)的客戶(hù)端提供程序。這些技術(shù)用Expression<T>參數(shù)定義了擴(kuò)展方法。這樣,訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的LINQ提供程序就可以讀取表達(dá)式,創(chuàng)建一個(gè)運(yùn)行期間優(yōu)化的查詢(xún),從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)。
后面會(huì)單獨(dú)介紹表達(dá)式樹(shù)的使用。

三.LINQ提供程序

.NET包含幾個(gè)LINQ提供程序。LINQ提供程序?yàn)樘囟ǖ臄?shù)據(jù)源實(shí)現(xiàn)了標(biāo)準(zhǔn)的查詢(xún)操作符。LINQ提供程序也許會(huì)實(shí)現(xiàn)比LINQ定義的更多擴(kuò)展方法,但至少要實(shí)現(xiàn)標(biāo)準(zhǔn)操作符。LINQ To XML實(shí)現(xiàn)了一些專(zhuān)門(mén)用于XML的方法,后面會(huì)詳細(xì)介紹。
LINQ提供程序的實(shí)現(xiàn)方案是根據(jù)名稱(chēng)空間和第一個(gè)參數(shù)的類(lèi)型來(lái)選擇的。實(shí)現(xiàn)擴(kuò)展方法的類(lèi)的名稱(chēng)空間必須是開(kāi)放的,否則擴(kuò)展方法就不在作用域內(nèi)。在LINQ to Objects中定義的Where()方法的參數(shù)和LINQ To Entities中定義的Where()方法的參數(shù)不同:
LINQ to Objects中定義的Where()方法:

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,Func<TSource,bool> predicate);

LINQ To Entities中定義的Where()方法:

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source,Expression<Func<TSource,bool>> predicate);

這兩個(gè)類(lèi)都在System.Linq的Syste,.Core程序集中實(shí)現(xiàn)。無(wú)論是用Func<TSource,bool>傳遞參數(shù),還是用Expression<Func<TSource,bool>>參數(shù)傳遞,lambda表達(dá)式都相同。只是編譯器的行為不同,它根據(jù)source參數(shù)來(lái)選擇。編譯器根據(jù)其參數(shù)選擇最匹配的方法。在A(yíng)DO.NET EF中定義的ObjectContext類(lèi)CreateQuery<T>()方法返回一個(gè)實(shí)現(xiàn)了IQueryable<TSource>接口的ObjectQuery<T>對(duì)象,因此EF使用Querable類(lèi)的Where()方法。

到此這篇關(guān)于c#中LINQ的基本用法的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

  • C#實(shí)現(xiàn)偽裝文件夾功能

    C#實(shí)現(xiàn)偽裝文件夾功能

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)偽裝文件夾的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • C#?winform實(shí)現(xiàn)多語(yǔ)言切換功能

    C#?winform實(shí)現(xiàn)多語(yǔ)言切換功能

    這篇文章主要為大家詳細(xì)介紹了如何使用C#?winform實(shí)現(xiàn)多語(yǔ)言切換功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解下
    2024-02-02
  • C#中使用Split方法拆分字符串實(shí)例

    C#中使用Split方法拆分字符串實(shí)例

    這篇文章主要介紹了C#中使用Split方法拆分字符串實(shí)例,本文給出了使用一個(gè)分隔符和多個(gè)分隔符拆分字符串的例子,需要的朋友可以參考下
    2014-08-08
  • C#制作多線(xiàn)程處理強(qiáng)化版網(wǎng)絡(luò)爬蟲(chóng)

    C#制作多線(xiàn)程處理強(qiáng)化版網(wǎng)絡(luò)爬蟲(chóng)

    這篇文章主要介紹了C#制作多線(xiàn)程處理強(qiáng)化版網(wǎng)絡(luò)爬蟲(chóng)的相關(guān)代碼,有想學(xué)習(xí)C#多線(xiàn)程編程的小伙伴可以參考下
    2016-09-09
  • C# JsonHelper 操作輔助類(lèi),拿來(lái)直接用

    C# JsonHelper 操作輔助類(lèi),拿來(lái)直接用

    本文總結(jié)了一些常用的JSON操作輔助類(lèi),包括轉(zhuǎn)換、判斷、Ajax異步等操作,希望能幫到大家。
    2016-05-05
  • 在c#中使用servicestackredis操作redis的實(shí)例代碼

    在c#中使用servicestackredis操作redis的實(shí)例代碼

    本篇文章主要介紹了在c#中使用servicestackredis操作redis的實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • C#特性-迭代器(上)及一些研究過(guò)程中的副產(chǎn)品

    C#特性-迭代器(上)及一些研究過(guò)程中的副產(chǎn)品

    這篇文章主要介紹了C#特性-迭代器(上)及一些研究過(guò)程中的副產(chǎn)品,需要的朋友可以參考下
    2014-12-12
  • C#實(shí)現(xiàn)的簡(jiǎn)單驗(yàn)證碼識(shí)別實(shí)例

    C#實(shí)現(xiàn)的簡(jiǎn)單驗(yàn)證碼識(shí)別實(shí)例

    這篇文章主要介紹了C#實(shí)現(xiàn)的簡(jiǎn)單驗(yàn)證碼識(shí)別實(shí)例,只適應(yīng)一些簡(jiǎn)單的驗(yàn)證碼,需要的朋友可以參考下
    2014-06-06
  • C#縮略圖多路徑多格式保存的實(shí)例

    C#縮略圖多路徑多格式保存的實(shí)例

    這篇文章介紹了C#縮略圖多路徑多格式保存的實(shí)例,有需要的朋友可以參考一下
    2013-07-07
  • 最新評(píng)論