2016-07-22 1 views
0

У меня есть огромная база устаревших кодов, и я бы хотел ее оптимизировать, сделать ее быстрее. По этой причине я подумал о поиске возможностей, где я могу заменить список и массивы с помощью HashSets и Dictionaries.NDepend поиск более быстрых возможностей сбора

Существует следующий запрос NDepend под .NET Framework Использование/System.collection

// <Name>Caution with List.Contains()</Name> 
let containsMethods = ThirdParty.Methods.WithFullNameIn(
    "System.Collections.Generic.List<T>.Contains(T)", 
    "System.Collections.Generic.IList<T>.Contains(T)", 
    "System.Collections.ArrayList.Contains(Object)") 

from m in Application.Methods.UsingAny(containsMethods) 
select m 

Этот запрос не достаточно. Это будет список одну функцию со следующим кодом:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace ListOptimisation 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int aLength = 10000; 
      List<int> aNumbers2Search = Enumerable.Range(0, aLength).ToList(); 

      List<int> aTestList = Enumerable.Range(0, aLength).ToList(); 
      int[] aTestArray = Enumerable.Range(0, aLength).ToArray(); 

      HashSet<int> aTestHash = new HashSet<int>(Enumerable.Range(0, aLength)); 
      Dictionary<int, int> aTestDictionary = new Dictionary<int, int>(); 
      for(int i = 0; i < aLength; ++i) 
      { 
       aTestDictionary.Add(i, i); 
      } 

      Search(aTestList, aNumbers2Search); 
      SearchIList(aTestList, aNumbers2Search); 
      SearchIEnumerable(aTestList, aNumbers2Search); 
      Search(aTestArray, aNumbers2Search); 
      SearchIList(aTestArray, aNumbers2Search); 
      SearchIEnumerable(aTestArray, aNumbers2Search); 
      Search(aTestHash, aNumbers2Search); 
      SearchIEnumerable(aTestHash, aNumbers2Search); 
      Search(aTestDictionary, aNumbers2Search); 
     } 

     private static void Search(List<int> testList_in, List<int> numbers2Search_in) 
     { 
      numbers2Search_in.ForEach(x => testList_in.Contains(x)); 
     } 

     private static void Search(HashSet<int> testHash_in, List<int> numbers2Search_in) 
     { 
      numbers2Search_in.ForEach(x => testHash_in.Contains(x)); 
     } 

     private static void Search(Dictionary<int, int> testDictionary_in, List<int> numbers2Search_in) 
     { 
      numbers2Search_in.ForEach(x => testDictionary_in.ContainsKey(x)); 
     } 

     private static void Search(int[] testArray_in, List<int> numbers2Search_in) 
     { 
      numbers2Search_in.ForEach(x => testArray_in.Contains(x)); 
     } 

     private static void SearchIList(IList<int> testIList_in, List<int> numbers2Search_in) 
     { 
      numbers2Search_in.ForEach(x => testIList_in.Contains(x)); 
     } 

     private static void SearchIEnumerable(IEnumerable<int> testIEnumerable_in, List<int> numbers2Search_in) 
     { 
      numbers2Search_in.ForEach(x => testIEnumerable_in.Contains(x)); 
     } 
    } 
} 

Лучше запрос будет такой:

// <Name>Caution with List style contains</Name> 
let containsMethods = ThirdParty.Methods.WithSimpleName("Contains").Except(ThirdParty.Methods.WithFullNameIn("System.Collections.Generic.HashSet<T>.Contains(T)")) 

from m in Application.Methods.UsingAny(containsMethods) 
select m 

//<Description> 
// Alternative to Caution with List.Contains() 
//</Description> 

Этот список будет 4 функции (Список, IList, INT [], IEnumerable). Я новичок относительно CQLinq. Мои вопросы:

  • ли какой-либо один может написать лучший запрос для выявления возможных плохих .NET контейнеров использований (не только содержит, но и для других возможных операций)?
  • Каким образом или вы обнаружите плохое использование контейнера?

Последний комментарий, некоторые из наших бизнес-логик обрабатывают много данных, поэтому правильные контейнеры, структуры данных и количество алгоритмов.

ответ

1

Это не очень хороший подход для оптимизации проблем с производительностью. Эта оптимизация будет оказывать незначительное влияние на вашу систему, если вы не имеете дело с огромными списками.

У вас будут лучшие результаты, используя performance profiling software. Если вы хотите выполнить производительность, выполнив поиск кода кода, попробуйте найти вложенные циклы и дорогой код, например, методы, связанные с файлами и базой данных.

+1

Это не микро-оптимизация, и мы смогли добиться огромного прироста производительности при перезаписи нескольких команд List <>, O (n). «Содержит» время для HashSet и Dictionary O (1) «.Contains» время. – Laszlo

+0

Как вы оцениваете улучшение производительности? Я знаю, что не отвечаю на ваш вопрос, но вы заявили о своей проблеме (производительности) и описали необычный подход к решению этой проблемы (и ваш запрос уже охватывает все релевантно содержит IMO). Может быть, вы должны отредактировать свой вопрос, предоставив больше информации о системе и как вы проводите этот процесс улучшения производительности. – lstern

+0

У нас есть тесты производительности, которые делают понятные для бизнеса сценарии, и они регистрируют свое время работы. И да, мы нашли пару узких мест с очень длинным и утомительным профилированием, и, в конце концов, это были плохие контейнеры. Мы не можем профилировать все, база кода огромна (миллионы строк), она для меня устарела. – Laszlo

1

Действительно пытаются заменить List<T>.Contains() звонки с Hashset<T>.Contains() вызовов не микро-оптимизации, и может значительно повысить производительность. Фактически рефакторинг алгоритма, основанного на использовании метода поиска O (1), - это, по моему опыту, одно из лучших действий для повышения производительности.

Запрошенный вами CQLinq запрос является первым шагом для определения некоторых потенциальных медленных точек. Однако, чтобы начать рефакторинг хорошо, вы должны 1) просмотрите код для оценки размера коллекции во время выполнения и 2) используйте performance profiling tool в реальной ситуации, чтобы оценить, влияют ли эти потенциальные медленные точки на производительность, а также найти других медленные точки, не соответствующие запросу.

+0

У нас есть тесты производительности бизнес-сценария, поэтому я могу проверить свои изменения, и я могу сопоставить измененный код с соответствующим тестом, так что это не проблема. :-) Моя последняя мечта, что кто-то ответит на мой второй вопрос с коллекцией «хорошо установленных» запросов CQLinq, называемых «узкими местами производительности». :-) – Laszlo

+0

Запрошенный вами запрос прав, но не будет совершенным. Если Hashset создан в методе и что ICollection .Contains() вызывается из другого метода на объекте ICollection , NDepend не будет достаточно умен, чтобы догадаться, что вызов функции Contains() прав, это статический анализатор, а не динамический анализатор ;-) –

+1

Да, мой запрос даст ложные срабатывания, но он будет содержать больше «запахов». И да NDepends не является динамическим анализатором, может быть, я должен поместить контрольную точку трассировщика в .NET List.Contains ... – Laszlo

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