Что является быстрым сравнением: Convert.ToInt32 (stringValue) == intValue или stringValue == intValue.ToString () - PullRequest
12 голосов
/ 16 декабря 2009

При разработке моего приложения я наткнулся на кое-что из сравнения:

    string str = "12345";
    int j = 12345;
    if (str == j.ToString())
    {
        //do my logic
    }

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

    string str = "12345";
    int j = 12345;
    if (Convert.ToInt32(str) == j)
    {
        //do my logic
    }

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

        var iterationCount = 1000000;
        var watch = new Stopwatch();
        watch.Start();
        string str = "12345";
        int j = 12345;
        for (var i = 0; i < iterationCount; i++)
        {
            if (str == j.ToString())
            {
                //do my logic
            }
        }
        watch.Stop();

И второй:

  var iterationCount = 1000000;
    var watch = new Stopwatch();
    watch.Start();
    string str = "12345";
    int j = 12345;
    for (var i = 0; i < iterationCount; i++)
    {
        if (Convert.ToInt32(str) == j)
        {
            //do my logic
        }
    }
    watch.Stop();

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

Ответы [ 8 ]

16 голосов
/ 17 декабря 2009

Ваш тест в корне ошибочен. Компилятор и среда выполнения - действительно умные звери и будут оптимизировать код как во время компиляции, так и во время выполнения (JIT-ing). В этом случае вы каждый раз делаете одно и то же , которое будет определено компилятором и оптимизировано, поэтому время будет одинаковым для каждого метода.

Попробуйте эту версию (у меня есть только .Net 2.0, отсюда и небольшие изменения):

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

namespace ToStringTest
{
    class Program
    {
        const int
            iterationCount = 1000000;

        static TimeSpan Test1()
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            string str = "12345";
            int j = 12345;
            for (int i = 0; i < iterationCount; i++)
            {
                if (str == i.ToString())
                {
                    //do my logic
                }
            }
            watch.Stop();
            return watch.Elapsed;
        }

        static TimeSpan Test2()
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            string str = "12345";
            int j = 12345;
            for (int i = 0; i < iterationCount; i++)
            {
                if (Convert.ToInt32(i) == j)
                {
                    //do my logic
                }
            }
            watch.Stop();
            return watch.Elapsed;
        }

        static void Main(string[] args)
        {
            Console.WriteLine("ToString = " + Test1().TotalMilliseconds);
            Console.WriteLine("Convert = " + Test2().TotalMilliseconds);
        }
    }
}

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

Вам необходимо знать, что делают различные операции, чтобы понять, какая из них быстрее.

Для преобразования строки в int требуется следующее:

total = 0
for each character in string
  total = total * 10 + value of charater

и ToString требует:

string = ""
while value != 0
  string.AddToFront value % 10
  value /= 10

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

Тогда есть сравнение, сравнение int - int просто, загрузите каждое значение в регистр и сравните - пара машинных инструкций, и все готово. Сравнение между двумя строками требует проверки каждого символа в строках по одному - в приведенном вами примере это было 5 байт (целое число, вероятно, 4 байта), что больше обращений к памяти.

13 голосов
/ 16 декабря 2009

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

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

Возьмите следующий пример: "00001" равно 1? Если вы хотите, чтобы он преобразовал строку в int с использованием Int.TryParse в комбинации, а затем сравнил их.

Могут быть и другие различия, в зависимости от местных настроек. Возможно, пользователь настроил форматирование чисел, например, «1,000,000» - если вы сравните эту строку с 1000000.ToString (), результат будет ложным.

6 голосов
/ 16 декабря 2009

Я предпочитаю i.ToString() == str, так как ничто не гарантирует, что Convert.ToInt32(str) не подведет.

3 голосов
/ 16 декабря 2009

Yikes, вы показываете, что логика вашего домена находится внутри цикла профилирования, поэтому вы не проверяли разницу во времени между версиями Convert и ToString вашего кода; вы тестировали объединенное время преобразования плюс выполнение вашей бизнес-логики. Если ваша бизнес-логика медленная и доминирует во времени конверсии, конечно, вы увидите одно и то же время в каждой версии.

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

Теперь, какую версию использовать: Вам нужно начать с указания именно того, что вы тестируете. Каковы ваши входы? "007" когда-нибудь будет входом? "007" отличается от целого числа 7? «1024» когда-нибудь будет входом? Есть ли проблемы с локализацией?

2 голосов
/ 16 декабря 2009

Семантика немного отличается. "01" == 1.ToString() is false , 1 == Convert.ToInt32("01") is true .

Если синтаксический анализ может пойти не так (строка не является допустимым числом), тогда Int32.TryParse быстрее, чем использовать Convert.ToInt32().

2 голосов
/ 16 декабря 2009

Если производительность почти идентична, используйте версию, которая более читабельна.

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

0 голосов
/ 16 декабря 2009

Хорошо, я продолжаю двигаться на шаг вперед и проверяю таким образом:

    int j = 123;
    for (var i = 0; i < iterationCount; i++)
    {
        j.ToString();
    }

второй: строка str = "123";

        for (var i = 0; i < iterationCount; i++)
        {
            Convert.ToInt32(str);
        }

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

0 голосов
/ 16 декабря 2009

Хорошо, для начала, первый, который преобразует int в строку, не выдаст ошибку, если строка, с которой сравнивается int, не конвертируется в int.

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

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