Вопрос о последствиях очень большой петли - PullRequest
2 голосов
/ 01 октября 2010

При циклическом просмотре очень большого языка (скажем, в C # 1.0), который, например, составляет 5 000 000 итераций цикла, какие проблемы это может вызвать (производительность / сборщик мусора и т. Д.).Это только для тела цикла.

Ответы [ 5 ]

3 голосов
/ 01 октября 2010

Следующий метод ничего не делает 5 000 000 раз:

public static void TestTest()
{            
  for(int i = 0; i != 5000000; ++i);
}

Компиляция приводит к следующему IL:

.method public hidebysig static void TestTest() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 num)
    L_0000: ldc.i4.0 
    L_0001: stloc.0 
    L_0002: br.s L_0008
    L_0004: ldloc.0 
    L_0005: ldc.i4.1 
    L_0006: add 
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: ldc.i4 0x4c4b40
    L_000e: bne.un.s L_0004
    L_0010: ret 
}

Работая на Pentium, я считаю, что он JITted для:

00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  push        eax  
00000004  cmp         dword ptr ds:[002030E4h],0 
0000000b  je          00000012 
0000000d  call        6CE7A839 
00000012  xor         edx,edx 
00000014  mov         dword ptr [ebp-4],edx 
00000017  xor         edx,edx 
00000019  mov         dword ptr [ebp-4],edx 
0000001c  nop              
0000001d  jmp         00000022 
0000001f  inc         dword ptr [ebp-4] 
00000022  cmp         dword ptr [ebp-4],4C4B40h 
00000029  jne         0000001F 
0000002b  nop              
0000002c  mov         esp,ebp 
0000002e  pop         ebp  
0000002f  ret

В основном это просто тратит свое время, увеличивая значение, сравнивая его с 5000000 и затем возвращая несколько байтов назад, если оно не равно.Скорее всего, все это будет в кеше L1.Возможно, это может быть немного более эффективно, чем это, если сборка с ручным кодированием, хотя, конечно, реальный способ ее оптимизации - игнорировать все это, но за исключением того, что это почти так же хорошо, как вы могли ожидать с любым языком.

В общем, не важен ни размер языка, ни сам цикл.

2 голосов
/ 01 октября 2010

Как все говорят, то, что происходит в теле цикла, является важной частью (и если это ваш вопрос, пожалуйста, напишите код / ​​псевдо-код).

Я написал приложения (в основном тестовые драйверы), которые распределяют, используют и располагают объекты внутри циклов, которые повторяются миллионы раз. Я считаю, что самый большой цикл, который я использовал, составлял не менее 15 миллионов циклов.

Конечное состояние машины было таким же, как и начальное состояние. «Хорошая производительность» субъективна, но я остался доволен результатами.

FWIW, существуют процессы, которые бесконечно зацикливаются в Windows, демонстрируя, что количество итераций может считаться несущественным во многих случаях. Именно то, что происходит внутри цикла, имеет значение, но современные процедуры распределения / распределения памяти (как ручные, так и автоматизированные с помощью GC) очень способны поддерживать разумный цикл.

Конечно, вы могли бы написать цикл занятости, чтобы преднамеренно умалять производительность системы, например открывать миллионы дескрипторов неуправляемым объектам и никогда не избавляться от этих дескрипторов в .Net.

РЕДАКТИРОВАТЬ: после просмотра IL / сборки Джона, похоже, что компилятор IL не оптимизирует цикл, даже если он пустой, поэтому я удалил эту теорию.

0 голосов
/ 01 октября 2010

В дополнение к другим опубликованным ответам, вам следует избегать помещения длительного цикла в поток пользовательского интерфейса / основной поток приложения с графическим интерфейсом.Это не имеет большого значения, если вы пишете консольное приложение, но оно имеет значение, если вы пишете приложение WinForms или WPF.

Отзывчивость пользовательского интерфейса приложений Windows зависит от обработки сообщений, и если вы получаетев длительный цикл for без «выхода в эфир», который время от времени обрабатывает оконные сообщения, ваш пользовательский интерфейс будет зависать, и ваш пользователь будет думать, что ваше приложение упало.

Вы можете добавить обработку сообщений втело вашего длительного цикла (Application.ProcessMessages в Delphi / C ++ VCL), но это приводит к новым проблемам с повторным входом - пользователь выбирает пункт меню в цикле for, ведущий к рекурсии.

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

0 голосов
/ 01 октября 2010

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

ЕслиВы обращаетесь к большому массиву в цикле, попробуйте получить к нему доступ линейным способом.Таким образом, данные, с которыми вы работаете, большую часть времени находятся в кеше памяти.Например, если вы перебираете двухмерный массив и имеете первый индекс в качестве внутреннего цикла, вы будете перепрыгивать туда-сюда в массиве, вызывая гораздо больше промахов в кеше.* создание строки в цикле работает очень плохо, так как вы будете перетасовывать все большие и большие строки каждую итерацию.Например, создание 10000 символьной строки путем добавления одного символа за раз занимает на моем компьютере 40 мс, но создание 100000 символьной строки занимает не 400 мс, а 8000 мс.

0 голосов
/ 01 октября 2010

ГХ работает за пределами вашего приложения, когда вы достигнете порога, он автоматически очистит все, что может. Все, что определено в области видимости тела цикла и не поддерживается в нижней области, будет помечено для завершения / сбора, когда GC посчитает, что это уместно.

Кроме этого, большой цикл (5 миллионов) не имеет реальных проблем с производительностью (по крайней мере, без дополнительной информации). Он будет просто повторяться и делать то, что делает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...