2009-10-29 2 views
5

У меня есть программа, написанная на C#, где есть много сравнений между ints и строками.Является ли более эффективным сравнение ints и ints или строк и строк

Итак, по соображениям производительности, я хотел бы просто узнать, что является более эффективным?

Если мы имеем:

int a = 5; 
string b = "5"; 

if(a == int.Parse(b)) { } 

ИЛИ

if(a.ToString() == b) { } 
+4

Ответ на запас на эти вопросы: Вы пробовали на самом деле профилировать его для ваших данных? –

+0

Im a noob:/Как я мог бы профилировать это? –

+0

Выполните оба варианта в цикле из нескольких тысяч или миллионов итераций и измерьте время, которое требуется. – Joey

ответ

4

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

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

Джефф Этвуд попросил сделать такой вид времени еще проще в this question. В этом вопросе и ответе вы найдете также хорошие примеры кода и подробные сведения.

Heres очень простой рабочий пример:

System.Diagnostics.Stopwatch sw=new System.Diagnostics.Stopwatch(); 


    int a = 5; 
    string b = "5"; 

    sw.Start(); 

    for (int i=0;i<1000000;i++) 
    { 
     if(a == int.Parse(b)) 
     { 

     } 
    } 

    sw.Stop(); 

    Console.WriteLine("a == int.Parse(b) milliseconds: " + sw.ElapsedMilliseconds); 

    sw.Reset(); 

    sw.Start(); 

    for (int i=0;i<1000000;i++) 
    { 
     if(a.ToString() == b) 
     { 

     }  
    }  

    sw.Stop(); 

    Console.WriteLine("a.ToString() == b milliseconds: " + sw.ElapsedMilliseconds); 

На моем компьютере она выводит:

A == int.Parse (б): 521 мс

a.ToString() = = b миллисекунд: 697

Итак, в этом простом сценарии int.Parse() немного быстрее, но недостаточно, чтобы действительно волноваться.

+0

в том, что класс отладки секундомера? soz im немного новичок, когда дело доходит до C# :) –

+1

Это класс System.Diagnostics.Stopwatch. Вы должны просто набрать: Секундомер sw = новый секундомер(); и начните его (это в System.dll). – Ash

+0

+1, это не случай использования «реального» профилировщика. – SoftMemes

1

Чем больше число, которое я пойду в первый метод. a. если b не является числом, он не сработает, прежде чем пытаться сравнить. b. строка сравнивается по длине и числу сразу.

0

Разбор строки в Int32 требует большей производительности и более чувствителен к ошибкам. Вы должны будете убедиться, что Int32.Parse будет успешным в первую очередь. Также вы можете использовать альтернативу для '=='. Используйте .Equals(), это легче читать и понимать.

if(b.Equals(a)) 
{ 

} 
+3

1.Equals ("1") скомпилирует, но возвращает false. Это не то, что он хочет. – SoftMemes

0

Также я прочитал Somwhere (MSDN), используя следующий быстрее, чем == для сравнения строк

StringA.ToUpperInvariant() == StringB.ToUpperInvariant() 
+0

В чем преимущество использования верхнего регистра при сравнении чисел? – Kobi

+0

То же самое, если бы это были строки? – 2009-10-29 10:32:46

+0

http://msdn.microsoft.com/en-us/library/ms973919.aspx – 2009-10-29 10:36:19

0

Есть много способов представления такого же числа в виде строки ...

7

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

Edit: Для тех, кто заинтересован, вот источник, быстрый 'п' загрязнен:

using System; 
using System.Diagnostics; 

namespace CompareTest 
{ 
    static class Program 
    { 
     static void Main(string[] args) 
     { 
      int iterations = 10000000; 
      int a = 5; 
      string b = "5"; 

      Stopwatch toStringStopwatch = new Stopwatch(); 
      toStringStopwatch.Start(); 

      for (int i = 0; i < iterations; i++) { 
       bool dummyState = a.ToString() == b; 
      } 

      toStringStopwatch.Stop(); 

      Stopwatch parseStopwatch = new Stopwatch(); 
      parseStopwatch.Start(); 

      for (int i = 0; i < iterations; i++) { 
       bool dummyState = a == int.Parse(b); 
      } 

      parseStopwatch.Stop(); 

      Console.WriteLine("ToString(): {0}", toStringStopwatch.Elapsed); 
      Console.WriteLine("Parse(): {0}", parseStopwatch.Elapsed); 
      Console.ReadLine(); 
     } 
    } 
} 
4

Ваш выбор между следующими
Листинг A

int a = 5; 
string b = "5"; 
//Assuming these two values are input received by the application at runtime 
int bInt; 
if (int.TryParse(b, NumberStyles.None, CultureInfo.InvariantCulture, out bInt) 
    && a.Equals(bInt)) 
{ 

} 

и

Листинг B

int a = 5; 
string b = "5"; 
//Assuming these two values are input received by the application at runtime 
if (string.Compare(b, a.ToString(), StringComparison.Ordinal) != -1) 
{ 

} 

Я испытал это с секундомером (как указано в выбранном ответе) и нашел код листинга гораздо быстрее. Но листинг B более читабельн!

Код листинга бьёт if(a == int.Parse(b))

1

Я сомневаюсь, либо вызов будет действительно существенно повлиять ваше приложение, если вы действительно создаете что-то на большом масштабе.

Оба метода создания новой строки, однако int.ToString() должен выполнять намного меньше задач, чем int.Parse().

int.ToString() выполняется внутренне в CLR (comnumber). int.Parse() делается внутри BCL source с использованием Number.ParseInt32() ->Number.StringToNumber() ->Number.ParseNumber().

ParseNumber выполняет огромное количество проверок, поэтому от пальца в воздухе догадывается, что вы можете представить int.ToString() быстрее. Как уже отмечали другие, лучшим способом будет узнать правильный тест производительности с классом StopWatch. Вы захотите попробовать это с ожидаемым числом чисел: десятичным, шестнадцатеричным.

Вы можете сравнить C++, что CLR использует для ToString() here: Посмотрите на

  • NumberToString (который используется для ToString() и другие форматы), который используется в FCIMPL3, вызывается междунар. ToString() как вызов extern.
  • Int32ToDecStr используется для форматирования «D».

C#

var x = 5.ToString("D"); 
var y = 5.ToString(); 

я мог быть неправ FCIMPL3, пожалуйста, поправьте меня, если я.

3

Внутренне ToString и Анализировать выполните следующие действия:

PARSE

value = 0 
for each char in string 
    value = value * 10 + valueof(char) // i.e. '0' -> 0, '7' -> 7 

ToString

string="" 
while value > 0 
    string.insert_at_front value % 10 // so that 0 -> '0' and 6 -> '6' 
    value /= 10 

// on IA32, the % and/can be done at the same time but requires 
// a 64bit source for 32bit values 

ToString должен быть медленнее, чем Parse, так как деление, как правило, медленнее, чем умножение. Однако вышеизложенное не учитывает какие-либо издержки, которые могут выполнять функции Parse и ToString во время преобразования (т. Е. Генерирование исключений, выделение памяти), что означает, что это не так ясно, что будет более оптимальным.

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

2

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

  1. Один из хорошо известных рисков с микро-тестов является то, что небольшое число повторений может в конечном итоге измерения шума (например, тайминги могут быть искажены входящей электронной почты или IM), но большое количество повторения могут в конечном итоге измерить производительность вашего сборщика мусора (например, если ваш код постоянно создает и отбрасывает строки).

  2. Когда я нахожусь в неудобном месте в коде, иногда полезно спросить себя: «Какие предположения или варианты поставили меня в такую ​​ситуацию? Что я мог сделать по-другому?» Например (просто угадывание), когда вы написали «... где много сравнений между int * [sic] * и строками», означает ли это, что вы можете использовать одни и те же значения повторно (например, сравнивая новые значения против предыдущих значений)? Если да, можете ли вы преобразовать каждую строку в int и кэшировать преобразованное значение для последующего повторного использования, вместо того, чтобы впоследствии преобразовать его?

2

Мой случай, который привел меня сюда было проверить, если «5» == 5 в распределительном регистре и потому, что я всегда буду получать числа от 0 до 9, я обнаружил, что самый быстрый способ: (int)b[0] == 53 Итак, я беру кулачный символ строки «5» (b [0]) и присваиваю ему значение ACSII, которое равно 53 и после этого сравнивается. Вот результаты: a == int.Parse(b) milliseconds: 194 a.ToString() == b milliseconds: 142 a == (int)(b[0]) milliseconds: 8 Несмотря на то, что это очень необычный случай, разница в массивном массиве очевидна;

EDIT: Как просил Дирк Хорстен. Неправильно, как и я. Я упомянул в своем посте, что я использую это в случае с коммутатором, поэтому буду использовать во всех своих случаях значения ASCII, чтобы он выглядел так: switch((int)b[0]) { case 48: Console.WriteLine("0"); break; case 49: Console.WriteLine("1"); break; case 50: Console.WriteLine("2"); break; case 51: Console.WriteLine("3"); break; case 52: Console.WriteLine("4"); break; case 53: Console.WriteLine("5"); break; case 54: Console.WriteLine("6"); break; case 55: Console.WriteLine("7"); break; case 56: Console.WriteLine("8"); break; case 57: Console.WriteLine("9"); break; } И для хорошего порядка здесь приведены результаты, как вы меня спрашивали: a == int.Parse(b) milliseconds: 184 a.ToString() == b milliseconds: 135 a + 48 ==(int)b[0] milliseconds: 8 Как вы могли видеть, нет такой большой разницы, просто добавляя одно дополнение.

+0

ваш ответ блестящий :), но неправильно :(Правильная вещь - 'a + 48 == (int) (b [0])', потому что '(int) (" 0 "[0]) == 48 '. Запустите свой тест с помощью этого кода и сообщите нам результаты. –

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