Что более быстро, включите строку или elseif на типе?

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

Но даже эта библиотека нуждается в хорошем знании спецификации модели Java-памяти, чтобы мы точно знали, что мы тестируем. Но я думаю, что в центре внимания этих усилий были mircobenchmarks. Не огромные бизнес-приложения.

75
задан Quibblesome 18 September 2008 в 16:57
поделиться

19 ответов

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

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

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

, если я выполняю следующее:

int value = 25124;
if(value == 0) ...
else if (value == 1) ...
else if (value == 2) ...
...
else if (value == 25124) ... 

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

switch(value) {
 case 0:...break;
 case 1:...break;
 case 2:...break;
 ...
 case 25124:...break;
}

выполнит один простой переход к корректному биту кода.

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

, Если оператор переключения является "достаточно небольшим" (то, где компилятор делает то, что это думает, является лучшим автоматически), включение строк генерирует код, который совпадает с если/еще цепочка.

switch(someString) {
    case "Foo": DoFoo(); break;
    case "Bar": DoBar(); break;
    default: DoOther; break;
}

совпадает с:

if(someString == "Foo") {
    DoFoo();
} else if(someString == "Bar") {
    DoBar();
} else {
    DoOther();
}

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

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

А, статическое поле определяется в "скрытом" месте, которое связано с классом, содержащим оператор переключения типа Dictionary<string, int>, и дано скорректированное имя

//Make sure the dictionary is loaded
if(theDictionary == null) { 
    //This is simplified for clarity, the actual implementation is more complex 
    // in order to ensure thread safety
    theDictionary = new Dictionary<string,int>();
    theDictionary["Foo"] = 0;
    theDictionary["Bar"] = 1;
}

int switchIndex;
if(theDictionary.TryGetValue(someString, out switchIndex)) {
    switch(switchIndex) {
    case 0: DoFoo(); break;
    case 1: DoBar(); break;
    }
} else {
    DoOther();
}

В некоторых быстрых тестах, которые я просто запустил, Если/Еще метод о 3x с такой скоростью, как переключатель для 3 различных типов (где типы случайным образом распределяются). В 25 типах переключатель быстрее маленьким полем (16%) в 50 типах, которые переключатель более двух раз как быстро.

, Если бы Вы собираетесь быть включением большого количества типов, я предложил бы 3-й метод:

private delegate void NodeHandler(ChildNode node);

static Dictionary<RuntimeTypeHandle, NodeHandler> TypeHandleSwitcher = CreateSwitcher();

private static Dictionary<RuntimeTypeHandle, NodeHandler> CreateSwitcher()
{
    var ret = new Dictionary<RuntimeTypeHandle, NodeHandler>();

    ret[typeof(Bob).TypeHandle] = HandleBob;
    ret[typeof(Jill).TypeHandle] = HandleJill;
    ret[typeof(Marko).TypeHandle] = HandleMarko;

    return ret;
}

void HandleChildNode(ChildNode node)
{
    NodeHandler handler;
    if (TaskHandleSwitcher.TryGetValue(Type.GetRuntimeType(node), out handler))
    {
        handler(node);
    }
    else
    {
        //Unexpected type...
    }
}

Это подобно тому, что предложенный Ted Elliot, но использование типа выполнения обрабатывает вместо полных текстовых объектов, избегает издержек загрузки текстового объекта посредством отражения.

Вот некоторые быстрые синхронизации на моей машине:

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 5 types
Method                Time    % of optimal
If/Else               179.67  100.00
TypeHandleDictionary  321.33  178.85
TypeDictionary        377.67  210.20
Switch                492.67  274.21

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 10 types
Method                Time    % of optimal
If/Else               271.33  100.00
TypeHandleDictionary  312.00  114.99
TypeDictionary        374.33  137.96
Switch                490.33  180.71

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 15 types
Method                Time    % of optimal
TypeHandleDictionary  312.00  100.00
If/Else               369.00  118.27
TypeDictionary        371.67  119.12
Switch                491.67  157.59

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 20 types
Method                Time    % of optimal
TypeHandleDictionary  335.33  100.00
TypeDictionary        373.00  111.23
If/Else               462.67  137.97
Switch                490.33  146.22

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 25 types
Method                Time    % of optimal
TypeHandleDictionary  319.33  100.00
TypeDictionary        371.00  116.18
Switch                483.00  151.25
If/Else               562.00  175.99

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 50 types
Method                Time      % of optimal
TypeHandleDictionary  319.67    100.00
TypeDictionary        376.67    117.83
Switch                453.33    141.81
If/Else               1,032.67  323.04

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

, Если, с другой стороны, вход составлен полностью типа, который проверяется сначала в, если/еще цепочка, что метод очень быстрее:

Testing 3 iterations with 5,000,000 data elements (mode=UniformFirst) and 50 types
Method                Time    % of optimal
If/Else               39.00   100.00
TypeHandleDictionary  317.33  813.68
TypeDictionary        396.00  1,015.38
Switch                403.00  1,033.33

С другой стороны, если вход всегда является последней вещью в, если/еще цепочка, это имеет противоположный эффект:

Testing 3 iterations with 5,000,000 data elements (mode=UniformLast) and 50 types
Method                Time      % of optimal
TypeHandleDictionary  317.67    100.00
Switch                354.33    111.54
TypeDictionary        377.67    118.89
If/Else               1,907.67  600.52

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

126
ответ дан Mani Gandham 7 November 2019 в 07:09
поделиться

Я могу пропускать что-то, но разве Вы не могли сделать оператора переключения на типе вместо Строки? Таким образом,

switch(childNode.Type)
{
case Bob:
  break;
case Jill:
  break;
case Marko:
  break;
}
-1
ответ дан Aeon 7 November 2019 в 07:09
поделиться

Включите строку, в основном компилируется в if-else-if лестничную структуру. Попытайтесь декомпилировать простой. В любом случае тестирование строкового равенства должно быть более дешевым, так как они интернируются и все, что было бы необходимо, проверка ссылки. Сделайте то, что имеет смысл с точки зрения пригодности для обслуживания; если Вы - строки compring, сделайте строковый переключатель. Если Вы выбираете на основе типа, лестничная структура типа является более соответствующим.

0
ответ дан nimish 7 November 2019 в 07:09
поделиться

Помните, профилировщик является Вашим другом. Любые догадки являются пустой тратой времени большую часть времени. BTW, у меня был хороший опыт с JetBrains профилировщик dotTrace .

0
ответ дан Eddie Velasquez 7 November 2019 в 07:09
поделиться

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

пз. Привычка вечности в качестве примера работает, потому что Вы не можете включить Типы. (Не я не знаю, почему точно, но мы попробовали его, это не работает. Это имеет отношение к типу, являющемуся переменным)

, Если Вы хотите протестировать это, просто создать отдельное приложение и создать два простых метода, которые делают то, что описано выше, и используйте что-то как Ildasm.exe для наблюдения IL. Вы заметите намного меньше строк в IL Метода оператора IF.

Ildasm идет с VisualStudio...

страница ILDASM - http://msdn.microsoft.com/en-us/library/f7dy01k1 (По сравнению с 80) Учебным руководством по .aspx

ILDASM - http://msdn.microsoft.com/en-us/library/aa309387 (По сравнению с 71) .aspx

0
ответ дан 7 November 2019 в 07:09
поделиться

Три мысли:

1), Если Вы собираетесь сделать что-то другое на основе типов объектов, могло бы иметь смысл перемещать то поведение в те классы. Тогда вместо переключателя или если еще, Вы просто назвали бы childNode. DoSomething ().

2) Выдерживающие сравнение типы будут намного быстрее, чем сравнения строк.

3) В, если еще дизайн, Вы могли бы быть в состоянии использовать в своих интересах переупорядочение тестов. Если объекты "Jill" составляют 90% объектов, проходящих там, теста для них сначала.

0
ответ дан Mark Bessey 7 November 2019 в 07:09
поделиться

Конечно, переключатель на Строке скомпилировал бы вниз в Сравнение строк (один на случай), который медленнее, чем сравнение типов (и намного медленнее, чем типичное целое число выдерживает сравнение, который используется для переключателя/случая)?

0
ответ дан JeeBee 7 November 2019 в 07:09
поделиться

Если типы, которые Вы включаете, являются примитивными типами.NET, можно использовать Тип. GetTypeCode (Тип), но если они - пользовательские типы, они все возвратятся как TypeCode. Объект.

словарь А с делегатами или классами обработчика мог бы работать также.

Dictionary<Type, HandlerDelegate> handlers = new Dictionary<Type, HandlerDelegate>();
handlers[typeof(Bob)] = this.HandleBob;
handlers[typeof(Jill)] = this.HandleJill;
handlers[typeof(Marko)] = this.HandleMarko;

handlers[childNode.GetType()](childNode);
/// ...

private void HandleBob(Node childNode) {
    // code to handle Bob
}
3
ответ дан Ted Elliott 7 November 2019 в 07:09
поделиться

Я вспоминаю чтение в нескольких справочниках, что, если/еще ветвление более быстро, чем оператор переключения. Однако немного исследования в области Blackwasp показывает, что оператор переключения на самом деле быстрее: http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx

В действительности, если Вы сравниваете типичные 3 - 10 (или так) операторы, я серьезно сомневаюсь, что существует любое реальное увеличение производительности с помощью один или другой.

, Поскольку Chris уже сказал, пойдите для удобочитаемости: , Что более быстро, включите строку или elseif на типе?

2
ответ дан Community 7 November 2019 в 07:09
поделиться

Если Вы уже не записали это и находите, что у Вас есть проблема производительности, я не волновался бы, о котором более быстро. Пойдите с тем, который это более читаемо. Помните, "Преждевременная оптимизация является корнем всего зла". - Donald Knuth

3
ответ дан Chris Upchurch 7 November 2019 в 07:09
поделиться

Попытайтесь использовать перечисления для каждого объекта, можно включить перечисления быстро и легко.

4
ответ дан Rick Minerich 7 November 2019 в 07:09
поделиться

Оператор переключения быстрее для выполнения, чем if-else-if лестничная структура. Это происходит из-за способности компилятора оптимизировать оператор переключения. В случае if-else-if лестничной структуры код должен обработать каждого если оператор в порядке, определенном программистом. Однако, потому что каждый случай в операторе переключения не полагается на более ранние случаи, компилятор в состоянии переупорядочить тестирование таким способом как для обеспечения самого быстрого выполнения.

12
ответ дан Nescio 7 November 2019 в 07:09
поделиться

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

6
ответ дан Gary Kephart 7 November 2019 в 07:09
поделиться

Конструкция ПЕРЕКЛЮЧАТЕЛЯ была первоначально предназначена для целочисленных данных; это полно решимости, должен был использовать аргумент непосредственно в качестве индекса в "таблицу отправки", таблицу указателей. По сути, был бы единственный тест, затем запустился бы непосредственно к соответствующим нормам, а не серии тестов.

трудность здесь состоит в том, что это - использование, был обобщен для "представления в виде строки" типов, которые, очевидно, не могут использоваться в качестве индекса, и все преимущество конструкции ПЕРЕКЛЮЧАТЕЛЯ потеряно.

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

3
ответ дан user17983 7 November 2019 в 07:09
поделиться

Во-первых, Вы сравниваете яблоки и апельсины. Необходимо было бы сначала выдержать сравнение, включают тип по сравнению с, включают строку, и затем если на типе по сравнению с если на строке, и затем сравнивают победителей.

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

, например,

class Node
{
    public virtual void Action()
    {
        // Perform default action
    }
}

class Bob : Node
{
    public override void Action()
    {
        // Perform action for Bill
    }
}

class Jill : Node
{
    public override void Action()
    {
        // Perform action for Jill
    }
}

Затем вместо того, чтобы делать оператор переключения, Вы просто называете childNode. Действие ()

17
ответ дан ilitirit 7 November 2019 в 07:09
поделиться

Я просто реализовал быстрое тестовое приложение и представил его с МУРАВЬЯМИ 4.
Спецификация:.Net 3.5 sp1 в Windows XP на 32 бита, код создается в режиме выпуска.

3 миллиона тестов:

  • Переключатель: 1,842 секунды
  • , Если: 0,344 секунды.

, Кроме того, результаты оператора переключения показывают (неудивительно), что более длинные имена занимают больше времени.

1 миллион тестов

  • Bob: 0,612 секунды.
  • Jill: 0,835 секунды.
  • Marko: 1,093 секунды.

я похож, "Если Еще" быстрее, по крайней мере, сценарий, я создал.

class Program
{
    static void Main( string[] args )
    {
        Bob bob = new Bob();
        Jill jill = new Jill();
        Marko marko = new Marko();

        for( int i = 0; i < 1000000; i++ )
        {
            Test( bob );
            Test( jill );
            Test( marko );
        }
    }

    public static void Test( ChildNode childNode )
    {   
        TestSwitch( childNode );
        TestIfElse( childNode );
    }

    private static void TestIfElse( ChildNode childNode )
    {
        if( childNode is Bob ){}
        else if( childNode is Jill ){}
        else if( childNode is Marko ){}
    }

    private static void TestSwitch( ChildNode childNode )
    {
        switch( childNode.Name )
        {
            case "Bob":
                break;
            case "Jill":
                break;
            case "Marko":
                break;
        }
    }
}

class ChildNode { public string Name { get; set; } }

class Bob : ChildNode { public Bob(){ this.Name = "Bob"; }}

class Jill : ChildNode{public Jill(){this.Name = "Jill";}}

class Marko : ChildNode{public Marko(){this.Name = "Marko";}}
18
ответ дан Greg 7 November 2019 в 07:09
поделиться

Я думаю, что основная проблема производительности здесь, что в блоке переключателя, Вы сравниваете строки, и что в, если еще блок, Вы проверяете на типы... Те два не являются тем же, и поэтому, я сказал бы, что Вы "сравниваете картофель с бананами".

я запустил бы путем сравнения этого:

switch(childNode.Name)
{
    case "Bob":
        break;
    case "Jill":
        break;
    case "Marko":
      break;
}

if(childNode.Name == "Bob")
{}
else if(childNode.Name == "Jill")
{}
else if(childNode.Name == "Marko")
{}
2
ответ дан SaguiItay 7 November 2019 в 07:09
поделиться

Сравнение строк будет всегда полагаться полностью на среду выполнения (если строки не будут статически выделены, хотя потребность сравнить тех друг с другом спорна). Сравнение типов, однако, может быть сделано посредством динамического или статического связывания, и так или иначе это более эффективно для среды выполнения, чем сравнение отдельных символов в строке.

0
ответ дан Magsol 7 November 2019 в 07:09
поделиться

Переключатель () скомпилирует еще для кодирования эквивалентный ряду IFS. Сравнения строк будут намного медленнее, чем сравнения типов.

2
ответ дан moonshadow 7 November 2019 в 07:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: