2015-07-10 2 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

Я не знаю, насколько это поможет, но вы можете захотеть кэшировать результат Года, а не выполнять вычисления каждый раз. – skaz

+0

@skaz Но кажется, что он не использовал Год для сортировки .... – HarryQuake

+0

Что такое 'items'? – sloth

ответ

2

Вы можете использовать AsParallel() в свою очередь.

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

Вопрос возникшие, если распараллеливание 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 Я не знаю, как это работает точно, но метод call AsParallel() разбивает ваш первоначальный список на несколько частей. Каждая часть обрабатывается собственным потоком. На двухъядерном процессоре производительность удваивается. Но обратите внимание, что это работает только для списков времени. Для небольших списков AsParallel() примерно в 200 раз медленнее! Из-за вызова дополнительного метода. – greenhoorn

+1

Путь к приятелю, спасибо за ценную информацию. – Vikas

Смежные вопросы