Странное поведение производительности

Я использую Visual Studio 2010 SP1, целевая платформа 2.0, целевая платформа: любой процессор, тестирование под Windows 7 x64 SP1.

Я испытываю странное поведение производительности.

Без app.config или со следующим app.config моя программа работает медленно (секундомер показывает ~ 0,11 с)

<?xml version="1.0"?>
<configuration>
  <startup >
    <supportedRuntime version="v2.0.50727" />
  </startup>
</configuration>

Следующий app.config ускоряет работу моей программы в 5 раз (секундомер показывает ~0,02 с)

<?xml version="1.0"?>
<configuration>
  <startup >
    <supportedRuntime version="v4.0.30319" sku=".NETFramework,Version=v4.0" />
  </startup>
</configuration>

Это код тестовой программы:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

class Program
{
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();

        while (true)
        {
            sw.Reset();
            sw.Start();

            for (int i = 0; i < 1000000; i++ )
            {
                "blablabla".IndexOf("ngrhotbegmhroes", StringComparison.OrdinalIgnoreCase);
            }

            Console.WriteLine(sw.Elapsed);
        }
    }
}

Я сижу часами и не могу понять, что здесь происходит. Есть идеи?


person DxCK    schedule 25.09.2011    source источник
comment
Сам класс System.String был изменен в .NET 4. С большим количеством работы над битами NLS в CLR. Вы не можете разумно ожидать подобных результатов, только надеяться.   -  person Hans Passant    schedule 25.09.2011


Ответы (3)


Похоже, вы только что обнаружили ситуацию, в которой .NET 4 работает намного быстрее. По умолчанию ваше приложение работает с платформой, для которой оно было создано. Когда вы заставляете использовать .NET 4, он работает быстрее. Это может быть улучшение JIT-компилятора, которое попало в вашу ситуацию, или это может быть улучшение структуры, но не следует слишком удивляться тому, что некоторые вещи в более новых версиях работают быстрее.

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

(И, как и Митч, я могу подтвердить, что вижу тот же эффект.)

РЕДАКТИРОВАТЬ: я только что исследовал это немного дальше и увидел интересный эффект... Я предполагаю, что мы вызываем haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase):

  • В .NET 2 результаты примерно такие же, как бы ни была велика «игла».
  • On .NET 4:
    • If needle is bigger than haystack (as per your example) .NET 4 is much faster than .NET 2
    • Если needle имеет тот же размер, что и haystack, .NET 4 немного немного медленнее, чем .NET 2.
    • Если needle меньше, чем haystack, .NET 4 намного медленнее, чем .NET 2.

(Это сохранение теста, в котором первый символ needle никогда не появляется в haystack, кстати.)

person Jon Skeet    schedule 25.09.2011
comment
Не должен ли Когда вы заставляете его использовать .NET читать Когда вы заставляете его использовать .NET 4? - person Ani; 25.09.2011
comment
Если игла меньше, чем стог сена, .NET 4 работает намного медленнее - тогда оптимизация кажется очень плохой. - person Henk Holterman; 25.09.2011
comment
@HenkHolterman: Действительно. Мне пришлось спешить после тестирования - если бы вы (или кто-то другой) могли воспроизвести это, это было бы полезно. - person Jon Skeet; 25.09.2011

Я только что провел ваш бенчмарк с несколькими настройками (которые включали больше итераций и усреднение) и могу подтвердить, что целевая версия .NET 4.0 действительно в 4-5 раз быстрее.

Так что предположительно IndexOf() был оптимизирован в .NET 4.0.

person Mitch Wheat    schedule 25.09.2011

Хорошо, некоторые тесты с новым VS11

n = 1000000;
string haystack = "ngrhotbegmhroes";
string needle = "blablablablablablablablablangrhotbegmhrobla bla";

.NET 4.5 :  8 ms
.NET 4.0 :  8 ms
.NET 3.5 : 45 ms
.NET 2.0 : 45 ms

Таким образом, эти первые результаты подтверждают ваши выводы, более новые версии работают быстрее.

Однако гораздо чаще искать короткую строку внутри большой строки:

n = 1000000; 
haystack = "blablablablablablablablablangrhotbegmhrobla bla";  
needle = "ngrhotbegmhroes";

.NET 4.5 : 1020 ms
.NET 4.0 : 1020 ms
.NET 3.5 :  155 ms
.NET 2.0 :  155 ms

И с гораздо более длинным стогом сена (~400 символов)

.NET 4.0 : 12100 ms
.NET 2.0 :  1700 ms

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


Все измерения доступны в конфигурации выпуска и профиле клиента.
Запуск из VS 11 с помощью Ctrl+F5
Win 7H, Core i7 2620M

person Henk Holterman    schedule 25.09.2011
comment
вау - это действительно странно - интересно, может ли какой-то внутренний элемент CLR/BCL что-то сказать об этом... - person Random Dev; 25.09.2011
comment
Какой вообще смысл искать длинную иголку в коротком стоге сена? Разве это не ЛОЖЬ по замыслу? - person yas4891; 25.09.2011
comment
@ yas4891: Да, но это был исходный вопрос, и у него совсем другая производительность. - person Henk Holterman; 25.09.2011
comment
Fwiw, .NET 4.5 не является параллельным, он перезаписывает .NET 4.0. То же самое с .NET 3.5 и 2.0. Вот почему сроки совпадают. Осторожнее с 4.5, с ней в пререлизе и долбя 4.0 никаких реальных выводов не сделаешь. - person Hans Passant; 25.09.2011
comment
@ Ганс, хорошо, я знал только о 3.5/2.0 . Дочитал до 4.5. - person Henk Holterman; 25.09.2011