2015-07-10 108 views
1

我有点再次卡住,因为我无法理解这一点。linq通过花费很长时间的顺序

所以我有一个名为类CSVItem

public class CSVItem 
{ 
    public int SortedAccountNumber { get; set; } 
    public DateTime Date { get; set; } 
    public int SNO { get; set; } 
    public string AccountNumber { get; set; } 
    public double Value { get; set; } 
    public int Year 
    { 
     get 
     { 
      if (Date.Month > MainWindow.fiscalMonth) 
      { 
       return Date.Year+1; 
      } 
      return Date.Year; 
     } 
    } 
    public int StaticCounter { get { return 1; } } 

    public CSVItem(string accNo, DateTime date, double value, int sNo) 
    { 
     Value = value;    
     Date = date; 
     AccountNumber = accNo; 
     SNO = sNo; 
    } 


} 

我读了CSV,和我做类型CSV项目的有500K左右项的列表。然后我尝试使用列表的默认Order By方法进行排序,并尝试从排序后的集合中返回列表。这里是代码:

List<CSVItem> items = new List<CSVItem>(); 

// ---- some code to read csv and load into items collection 

List<CSVItem> vItems = items.OrderBy(r1 => r1.AccountNumber).ThenBy(r1 => r1.Date).ToList(); 

这就像是永远排序,然后将集合转换回列表。那么我肯定已经尝试过加载大约一百万条记录,而且从来没有从Linq Sorting那里得到过这样的回应 - 这有点让我发疯。我可以在哪里找到解决问题的任何帮助或建议?

+0

我不知道这会有多大帮助,但您可能需要缓存Year的结果,而不是每次都进行计算。 – skaz

+0

@skaz但似乎他没有使用年来排序.... – HarryQuake

+0

什么是'项目'? – sloth

回答

2

您可以使用AsParallel()您的优势。

List<CSVItem> vItems = items.AsParallel().OrderBy(r1 => r1.AccountNumber).ThenBy(r1 => r1.Date).ToList(); 

问题arised,如果OrderBy()并行确实有副作用如果它后跟一个ThenBy()

AsParallel()什么时候拆分IEnumerable?有2个可能的答案。让我们给定的查询:

items.AsParallel().OrderBy(x=>x.Age).ThenBy(x=>x.Size) 

选项1

该项目将分割,每个部分都被按年龄排序,然后按大小,最后合并到1名名单。显然不是我们想要的。

选项2

该项目将分割,每个部分都被按年龄排序,项目合并到1名名单。之后,项目再次拆分,按大小排序并合并回1个列表。这就是我们想要的。

我创建了一个小例子来检查,哪一个是真的。

using System; 
using System.Collections.Generic; 
using System.Linq; 

public class Program 
{ 
    static void Main(string[] args) 
    { 
     List<TestItem> items = new List<TestItem>(); 
     List<TestItem> itemsNonParallel = new List<TestItem>(); 

     items.Add(new TestItem() { Age = 1, Size = 12 }); 
     items.Add(new TestItem() { Age = 2, Size = 1 }); 
     items.Add(new TestItem() { Age = 5, Size = 155 }); 
     items.Add(new TestItem() { Age = 23, Size = 42 }); 
     items.Add(new TestItem() { Age = 7, Size = 32 }); 
     items.Add(new TestItem() { Age = 9, Size = 22 }); 
     items.Add(new TestItem() { Age = 34, Size = 11 }); 
     items.Add(new TestItem() { Age = 56, Size = 142 }); 
     items.Add(new TestItem() { Age = 300, Size = 13 }); 

     itemsNonParallel.Add(new TestItem() { Age = 1, Size = 12 }); 
     itemsNonParallel.Add(new TestItem() { Age = 2, Size = 1 }); 
     itemsNonParallel.Add(new TestItem() { Age = 5, Size = 155 }); 
     itemsNonParallel.Add(new TestItem() { Age = 23, Size = 42 }); 
     itemsNonParallel.Add(new TestItem() { Age = 7, Size = 32 }); 
     itemsNonParallel.Add(new TestItem() { Age = 9, Size = 22 }); 
     itemsNonParallel.Add(new TestItem() { Age = 34, Size = 11 }); 
     itemsNonParallel.Add(new TestItem() { Age = 56, Size = 142 }); 
     itemsNonParallel.Add(new TestItem() { Age = 300, Size = 13 }); 

     foreach (var item in items.AsParallel().OrderBy(x => x.Age).ThenBy(x => x.Size)) 
     { 
      Console.WriteLine($"Age: {item.Age}  Size: {item.Size}"); 
     } 

     Console.WriteLine("---------------------------"); 

     foreach (var item in itemsNonParallel.OrderBy(x => x.Age).ThenBy(x => x.Size)) 
     { 
      Console.WriteLine($"Age: {item.Age}  Size: {item.Size}"); 
     } 

     Console.ReadLine();   
    } 
} 

public class TestItem 
{ 
    public int Age { get; set; } 
    public int Size { get; set; } 
} 

结果

AsParallel()做我们想要的。它首先处理OrderBy()并行,将列表合并回来,然后转到下一个查询,在我们的案例中为ThenBy()。我多次测试并始终得到相同的结果。

+0

谢谢@greenhoorn。有效。你能解释它背后的概念吗?它太快了...... – Vikas

+0

@Vikas我不知道它是如何工作的,但方法调用AsParallel()将原始列表拆分为几个部分。每个部分都由自己的线程处理。在双核cpus上,性能提高了一倍。但请注意,这只适用于时间表清单。对于小列表AsParallel()约慢200倍!由于附加的方法调用。 – greenhoorn

+1

去哥们的路,感谢宝贵的资讯。 – Vikas