2015-06-02 2 views
1

У меня есть большой для цикла (30k максимум итераций), что, кажется, постоянно замедляется:.net большой цикл замедляя

  • Первые тысячи итераций принимают 1.34s
  • После 12k итераций, следующие тысячи принять 5.31s
  • После 23K итераций, следующая тысяча принять 6.65s
  • последние тысячи итераций принимают 7.43s

Для того, чтобы получить небольшую производительность, я переключился с цикла на цикл for и попробовал настройку выпуска, но я не могу найти что-либо еще в this question, который применим ко мне. Петля находится в асинхронном методе

Почему цикл замедляется? Можно ли этого избежать?

for(int iter = 0; iter < LargeList1.Count; iter++) 
{ 
    var cl_from = LargeList1[iter]; 
    if(LargeList2.Any(cl => cl.str.Contains(cl_from.str))) 
    { 
     DateTime dt1 = //last write time of a file 
     DateTime dt2 = //last write time of a different file 
     if(DateTime.Compare(dt1, dt2) > 0) 
     { 
      try 
      { 
       CopyFile(//Kernel32 CopyFile a file overwrite); 
       globals.fileX++; 
      } 
      catch(Exception filexx) 
      { 
       //error handler 
      } 
     } 
     else 
     { 
      globals.fileS++; 
     } 
    } 
    else 
    { 
     Directory.CreateDirectory(//create a directory, no check if it already exists); 
     try 
     { 
      CopyFile(//Kernel32 CopyFile a file do not overwrite); 
      globals.fileX++; 
     } 
     catch(Exception filex) 
     { 
      // error handler 
     } 

    } 
    gui.UpdateCount(globals.fileF, globals.fileX, globals.fileS); //updates iteration on textboxes 
    float p = (float)100.0*((float)globals.fileF + (float)globals.fileX + (float)globals.fileS)/(float)globals.totalCount; 
    gui.setProgress(p); //updates progressbar 
} 

Edit: как многие предложили, используя hashset.Contains (cl_from.str) решить эту проблему.

+0

Что означает «итерации n-m take x»? Означает ли это * в любое время есть много итераций *, или * первые и последние c итерации принимают *? –

+0

итерации 29k-30k принимают 7.43s означает, что последние 1000 итераций занимают 7.43 секунды. Я обновлю его, чтобы уточнить – Alex

+0

Является ли это '7.43s' от начала итерации, или' 7.43s' от 'iteration 29k' до' iteration 30k'? –

ответ

3

Характер этих двух предметов, я могу себе представить, будет узким местом.

for(int iter = 0; iter < LargeList1.Count; iter++) 
{ 
    ..... 
    if(LargeList2.Any(cl => cl.str.Contains(cl_from.str))) 
    ........... 

Вы проверяете, есть ли какое-либо слово из другого большого списка, содержится в текущей строке.

Несколько причин, почему это, вероятно, происходит медленнее, с течением времени:

  1. Первоначально его быстрее, потому что GC оленья кожа работает как много, как вы получите дальше в цикле, GC должен собрать все чаще и чаще.
  2. Длина строки cl_from.st, возможно, увеличивается?

Некоторые моменты, рассмотреть следующие вопросы:

  1. Насколько велика cl_from.str и LargeList2, стоит создать хэш всех возможных значений в cl_from.str, а затем проверить, что есть поиск или, возможно, даже создание хэш набор всех строк LargeList2, а затем использовать это, итерации по каждой комбинации строки в cl_From.str.

  2. Возможно, вы хотите улучшить алгоритм поиска, например. проверьте C# .NET: FASTEST WAY TO CHECK IF A STRING OCCURS WITHIN A STRING. Или google для других индексирования/алгоритма строкового поиска. Почему бы не использовать что-то вроде Lucene.NET?

  3. Используйте профилировщик .NET, чтобы узнать, где находится узкое место, и где он проводит время.

+0

. Я попробую ваши предложения. cl_from.st не растет во время цикла, я предполагаю, что это GC и содержит. – Alex

+0

Использование hashset.Contains (cl_from.str) решило проблему. – Alex

0

Я уверен, что виновный линия будет:

if(LargeList2.Any(cl => cl.str.Contains(cl_from.str))) 

«Любой» метод расширения с лямбда-выражения в конечном счете будет медленнее, чем обыкновенное письмо версии из-за накладных расходов на анонимный делегировать, так что вы могли бы попробовать расширения из таких образа:

foreach (var cl in LargeList2) 
{ 
    if (cl.str.Contains(cl_from.str)) 
    { 
     // do stuff 
     break; 
    } 
} 

Но я думаю, что эта итерация, где вы можете найти медленность закрадывается, что с анонимным делегатом и струнным Functio п. Вероятно, итерация должна работать через большую часть LargeList2, чтобы найти соответствие по мере продолжения итерации, что означает медленное снижение производительности по мере продолжения процесса.

Попробуйте использовать профилировщик производительности ANTS с таймингами линейного уровня, которые позволяют увидеть, показывает ли эта строка в качестве точки доступа после запуска этого процесса.

+0

'Any' в основном компилируется на это. Единственным отличием является '// do stuff', это будет' return true; ' – TyCobb

+0

Попробуйте большой тест в консольном приложении с синхронизацией ... для следующего цикла с методом сравнения внутри или с расширением enumerator, например. . Где (x => x.Prop> значение) ... первое выигрывает! –

0

Другая возможность заключается в том, что файловая система вызывает у вас проблемы. Если у вас есть тысячи файлов в одной папке, открытие файла может занять очень много времени. Система загружает каталог и выполняет последовательный поиск, чтобы найти запись для запрошенного файла.

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

foreach (var filename in Directory.GetFiles(...)) 
{ 
    // start stopwatch 
    // open the file 
    // stop stopwatch 
    // display time 
    // close the file 
} 

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

Решение заключается в том, чтобы сломать вещи, чтобы у вас не было так много файлов в папке. Вместо 10 000 файлов в одной папке есть 100 папок по 100 файлов. Или 10 папок по 1000 файлов каждый. Либо будет намного быстрее, чем одна папка с огромным количеством файлов.

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