Что быстрее всего: (int), Convert.ToInt32 (x) или Int32.Parse (x)?

Какой из следующих кодов является самым быстрым / лучшим методом преобразования некоторого объекта x?

int myInt = (int)x;

or

int myInt = Convert.ToInt32(x);

or

int myInt = Int32.Parse(x);

или в случае строки 's'

int myInt;
Int32.TryParse(s, out myInt);

Мне любопытно, какой из них работает быстрее всего для типов данных, у которых есть метод в Convert, а не только для целых чисел. Я просто использовал int в качестве примера.

Изменить: этот случай возник из-за получения информации из таблицы данных. Будет ли (int) работать быстрее всех?

Из некоторых тестов, когда объект x = 123123123, int работает быстрее всего, как многие говорили. Когда x является строкой, Parse выполняется быстрее всего (примечание: приведение вызывает исключение). Что мне действительно любопытно, так это то, как они работают, когда значение извлекается следующим образом:

foreach(DataRow row in someTable.Rows)
{
    myInt = (int)row["some int value"];
    myInt2 = Int.Parse(row["some int value"]);
    myInt2 = Convert.ToInt32(row["some int value"]);
}

person Dan McClain    schedule 12.03.2009    source источник
comment
Обсуждение stackoverflow.com/questions/586436/ может быть полезным   -  person Jeff Moser    schedule 12.03.2009
comment
кажется маловероятным, что эта часть программы является вашим узким местом, когда у вас есть запросы к БД.   -  person David Heffernan    schedule 17.07.2011


Ответы (15)


Почему бы тебе просто не попробовать пару тысяч раз?

(это относится ко всем вопросам "Что быстрее всего:")


Хммм, много отрицательных голосов за эти годы ... Думаю, мне следует расширить этот ответ.

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

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

И если сегодня это преобразователь object-int, завтра, возможно, вы подумаете, что ваш преобразователь object-DateTime требует много времени. Не могли бы вы создать еще один вопрос SO, чтобы узнать, какой метод самый быстрый?

Что касается вашей ситуации (без сомнения, уже давно решенной), как упоминалось в комментарии, вы запрашиваете базу данных, поэтому преобразование объект-int - наименьшая из ваших проблем. На вашем месте я бы использовал любой из упомянутых вами методов преобразования. Если возникает проблема, я бы изолировал вызов, используя профилировщик или ведение журнала. Затем, когда я замечаю, что преобразование object-int выполняется миллион раз и общее время, затрачиваемое на это преобразование, кажется относительно большим, я бы перешел на другой метод преобразования и перепрофилировал. Выберите метод преобразования, который занимает меньше всего времени. Вы даже можете протестировать это в отдельном решении, или даже в LINQPad, или Powershell и т. Д.

person demoncodemonkey    schedule 12.03.2009
comment
Я думаю, что несколько миллионов раз может быть лучше. - person WakeUpScreaming; 12.03.2009
comment
Сделайте это миллиардом, пока вы это делаете;) - person Binoj Antony; 13.03.2009
comment
Я думаю, что лучше получить такой ответ здесь, в SO. Так что тысячам людей, которые хотят знать, не нужно бегать тысячу раз. Это НЕ лучший вопрос, но его проверили более 8 тысяч человек. - person Michel Ayres; 04.04.2013
comment
@Demoncodemonkey То, что вы говорите, правда, но это не ответ. - person Yehuda Shapira; 23.04.2014
comment
Я не согласен с вами, в случае, если этот вопрос сэкономит много времени людям на try it a couple of thousand times. Вместо этого, если вы ответите правильно, я сэкономлю время на прокрутку вниз. - person nyconing; 11.01.2018
comment
Если каждый должен провести тест, чтобы увидеть, какой метод является самым быстрым, то есть много потраченного впустую времени (в сумме), поэтому с точки зрения программиста было бы более эффективно дать один полезный ответ, на который каждый может взглянуть за пару секунд, не прерывая то, что они делали раньше. - person Alexandre Daubricourt; 26.02.2019

Это зависит от того, что вы ожидаете от x

Если x - это целое число в коробке, тогда (int)x будет самым быстрым.

Если x - строка, но определенно действительное число, тогда int.Parse(x) лучше всего

Если x - строка, но она может быть недействительной, тогда int.TryParse(x) намного быстрее, чем блок try-catch.

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

Если вы не знаете, что такое x (может быть, строка или int в рамке), тогда Convert.ToInt32(x) лучше всего.

Эти обобщенные правила также верны для всех типов значений со статическими методами Parse и TryParse.

person Keith    schedule 12.03.2009
comment
что означает "вставленное целое"? - person Soheila Tarighi; 26.07.2020
comment
@SoheilaTarighi, если у вас есть object x = 1234;, мы бы сказали, что это в коробке - в основном .NET имеет int (тип значения), хранящийся в object (ссылочный тип), мы называем это блоком . Если у вас есть object x = 1234;, тогда (int) x просто распакует его, но у вас может быть object x = 1234; x = "abcd";, а затем (int) x выдаст исключение. - person Keith; 28.07.2020

Самый быстрый! = Лучшая практика!

Например, (int) почти наверняка самый быстрый, потому что это оператор, а не вызов функции, но он будет работать только в определенных ситуациях.

Лучше всего использовать максимально читаемый код, который не повлияет отрицательно на вашу производительность, и в 99 случаях из 100 целочисленное преобразование не влияет на производительность вашего приложения. Если это так, используйте наиболее подходящее и самое узкое преобразование, которое вы можете. Иногда это (int). Иногда это TryParse(). Иногда Convert.ToInt32().

person Joel Coehoorn    schedule 12.03.2009

Если вы знаете, что данные определенно имеют тип int, тогда int myInt = (int)x; должен быть самым быстрым вариантом. В противном случае TryParse поможет вам исправить это без медлительности исключений.

КСТАТИ :

(int) только распаковывает, поэтому быстрее,

(int) IL =

  .locals init (
        [0] object x,
        [1] int32 Y)
    L_0000: ldc.i4.1 
    L_0001: box int32
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: unbox int32
    L_000d: ldobj int32
    L_0012: stloc.1 
    L_0013: ret 

Convert.Toint32 =

.locals init (
        [0] object x,
        [1] int32 Y)
    L_0000: ldc.i4.1 
    L_0001: box int32
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
    L_000d: call int32 [mscorlib]System.Convert::ToInt32(object)
    L_0012: stloc.1 
    L_0013: ret 
person dr. evil    schedule 12.03.2009
comment
Yeah (int)! = Convert.ToInt32, Gatekiller, должно быть, курит плохую штуку :) +1 - person leppie; 12.03.2009

Когда у меня возникают вопросы о различиях в производительности между различными способами выполнения чего-то конкретного, я обычно делаю новую запись в своей копии MeasureIt, которую можно бесплатно загрузить с отличного статья MSDN от Вэнса Моррисона. Для получения дополнительной информации обратитесь к статье.

Добавляя простой фрагмент кода в MeasureIt, я получаю результаты ниже, в которых сравниваются фактические тайминги различных методов преобразования в int. Обратите внимание, что приведение строки к int вызовет исключение и недействительно, поэтому я просто добавил перестановки, которые имели для меня смысл.

 
Name                                                Median   Mean     StdDev   Min      Max    Samples       
IntCasts: Copy [count=1000 scale=10.0]              0.054    0.060    0.014    0.054    0.101    10       
IntCasts: Cast Int [count=1000 scale=10.0]          0.059    0.060    0.007    0.054    0.080    10       
IntCasts: Cast Object [count=1000 scale=10.0]       0.097    0.100    0.008    0.097    0.122    10       
IntCasts: int.Parse [count=1000 scale=10.0]         2.721    3.169    0.850    2.687    5.473    10       
IntCasts: Convert.ToInt32 [count=1000 scale=10.0]   3.221    3.258    0.067    3.219    3.418    10     


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

static unsafe public void MeasureIntCasts()
{
    int result;
    int intInput = 1234;
    object objInput = 1234;
    string strInput = "1234";

    timer1000.Measure("Copy", 10, delegate
    {
        result = intInput;
    });
    timer1000.Measure("Cast Object", 10, delegate
    {
        result = (int)objInput;
    });

    timer1000.Measure("int.Parse", 10, delegate
    {
        result = int.Parse(strInput);
    });

    timer1000.Measure("Convert.ToInt32", 10, delegate
    {
        result = Convert.ToInt32(strInput);
    });
}
person Eric Cosky    schedule 13.03.2009
comment
Как насчет среднего тоже? Увеличить размер выборки как минимум до «реального значения», например, 10000. - person leppie; 13.03.2009
comment
Вы также создаете массу накладных расходов, используя замыкания. - person leppie; 13.03.2009

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

person Surgical Coder    schedule 12.03.2009
comment
Я согласен. Думать о безопасности важнее скорости. - person Jordan Parmer; 12.03.2009
comment
Но если вы знаете, что он приведет к преобразованию или синтаксическому анализу в int, вам не нужно беспокоиться об исключении. - person Samuel; 12.03.2009
comment
Откуда вы знаете? Если x не является int, вы никогда не сможете узнать наверняка! - person Tundey; 12.03.2009
comment
При извлечении данных из столбца ненулевого типа int в базе данных с помощью средства чтения данных вы можете знать, что это данные типа int. - person sgriffinusa; 12.03.2009
comment
С SQLite вы можете ожидать int, а на самом деле получить long. Приведение (int) cmd.ExecuteScalar () может завершиться ошибкой, если возвращаемое значение является длинным. Это касается получения первичных ключей int, а также выбора count (*). - person Elan; 12.03.2011
comment
@JordanParmer Иногда производительность важнее, чем безопасность. Подумайте, когда вам нужно перебрать миллионы буферов. - person nyconing; 11.01.2018

При оптимизации сетки связанных данных в .Net 2 я обнаружил, что почти половина времени тратится на методы ToString () различных объектов, которые затем использовались в качестве входных данных для операций преобразования. Изоляция этих случаев и приведение к правильному типу, где это возможно (поскольку это были строки, взятые из базы данных, и на типы можно было положиться), это привело к значительному увеличению скорости этой операции привязки данных.

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

person fractos    schedule 13.03.2009

Расширяя тест Эрика Коски с помощью альтернатив Сэма Аллена, я обнаружил, что если вы знаете, что ваша строка является действительным целым числом, то анализировать ее самостоятельно намного быстрее.

Я расширил тест на следующие случаи:

    timer1000.Measure("IntParseFast", 10, delegate
    {
        result = Misc.IntParseFast(strInput);
    });

    timer1000.Measure("IntParseUnsafe", 10, delegate
    {
        result = Misc.IntParseUnsafe(strInput);
    });

Со следующими реализациями:

public static int IntParseFast(string value)
{
    int result = 0;
    int length = value.Length;
    for (int i = 0; i < length; i++)
    {
        result = 10 * result + (value[i] - 48);
    }
    return result;
}

public unsafe static int IntParseUnsafe(string value)
{
    int result = 0;
    fixed (char* v = value)
    {
        char* str = v;
        while (*str != '\0')
        {
            result = 10 * result + (*str - 48);
            str++;
        }
    }
    return result;
}

Получаю следующие результаты:

IntCaint.Parse                5,495
IntCaConvert.ToInt32          5,653
IntCaIntParseFast             1,154
IntCaIntParseUnsafe           1,245
person Janosch    schedule 17.07.2011

это неправда. Быстрое преобразование - это прямое приведение:

int i = (int) stringData;

watch.Elapsed = {00:00:00.1732388}
watch2.Elapsed= {00:00:00.0878196}


 // Mesary start
                Stopwatch watch = new Stopwatch();

                watch.Start();
                for (int f = 1; f < 1000000; f++)
                {
                    item.Count = FastInt32.IntParseFast(dt.Rows[i]["TopCount"]);
                }   // Execute the task to be timed
                watch.Stop();

                Console.WriteLine("Elapsed: {0}", watch.Elapsed);
                Console.WriteLine("In milliseconds: {0}", watch.ElapsedMilliseconds);
                Console.WriteLine("In timer ticks: {0}", watch.ElapsedTicks);
                // Mesary end


                // Mesary start
                Stopwatch watch2 = new Stopwatch();

                watch2.Start();
                for (int n = 1; n < 1000000; n++)
                {
                    item.Count = (int)(dt.Rows[i]["TopCount"]);
                }   // Execute the task to be timed
                watch2.Stop();

                Console.WriteLine("Elapsed: {0}", watch2.Elapsed);
                Console.WriteLine("In milliseconds: {0}", watch2.ElapsedMilliseconds);
                Console.WriteLine("In timer ticks: {0}", watch2.ElapsedTicks);
                // Mesary end
person pet    schedule 27.02.2013

Не уверен в производительности, но это совсем не те методы. И Parse, и TryParse работают со строкой, String представление объекта анализируется (см. MSDN).

Преобразует строковое представление числа в эквивалентное ему 32-битовое целое число со знаком.

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

Матиас

person Matthias Meid    schedule 12.03.2009

Если бы вам потребовалась дополнительная скорость, было бы легко протестировать различные варианты. Поскольку вы их не тестируете, они вам не понадобятся. Не тратьте время на бессмысленные микрооптимизации!

person dan-gph    schedule 12.03.2009

(int) преобразование в строку не будет работать, поэтому я его не тестирую. Convert.ToInt32 отражает проверку значения на null и ЗАТЕМ вызов int.Parse, поэтому в целом он должен быть медленнее, чем int.Parse ().

person nothrow    schedule 12.03.2009

foreach(DataRow row in someTable.Rows)
{
    myInt = (int)row["some int value"];
    myInt2 = Int.Parse(row["some int value"]);
    myInt2 = Convert.ToInt32(row["some int value"]);
}

В этом примере, если значение, полученное из таблицы, действительно является значением типа int или сопоставимым значением базы данных, то с помощью

myInt = (int)row["some int value"];

будет наиболее эффективным и, следовательно, самым быстрым, поскольку

row["some int value"];

будет экземпляром типа значения int, помещенным внутри экземпляра объекта ссылочного типа, поэтому использование явного приведения типа будет самым быстрым, потому что другие люди сказали, что это операция, а не вызов функции, тем самым сокращая требуемые операции процессора. Вызов метода преобразования или синтаксического анализа потребует дополнительных операций с процессором и, следовательно, не будет таким «быстрым».

person GriehmForTheWin    schedule 08.01.2013

Кто-то уже провел сравнительный анализ. Вот результаты. Самый быстрый способ, если вы знаете, что то, что вы конвертируете, всегда будет действительным int, - это использовать следующий метод (на который несколько человек ответили выше):

int value = 0;
for (int i = 0; i < str.Length; i++)
{
    value = value * 10 + (str[i] - '0');
}

Другие методы, которые были протестированы были:

  • Convert.ToInt32
  • Int32.TryParse
  • int.Parse
person Community    schedule 23.09.2014

В конце концов, все они звонят:

System.Number.ParseInt32(string s, NumberStyles style, NumberFormatInfo info);

Таким образом, не будет никакой разницы, что бы это ни было.

Загляните в .Net Reflector, чтобы увидеть это.

person GateKiller    schedule 12.03.2009
comment
действительно ли (int) x вызывает Int32.Parse ()? И второй вопрос: что делает код перед вызовом Int32.Parse (), что также влияет на производительность. - person dr. evil; 12.03.2009
comment
(int) - это просто сокращение от Convert.ToInt32, который вызывает System.Number.ParseInt32 (). Вообще никакой разницы. Любая разница в производительности будет измеряться только в пикосекундах. - person GateKiller; 12.03.2009
comment
GateKiller: Я называю BS, это просто кастом и распаковка. - person leppie; 12.03.2009
comment
У Try Parse также есть внутренняя функция try catch для реализации, которая, хотя и небольшая, но по-прежнему является накладной, что делает ее медленнее (на пикосекунды), чем синтаксический анализ, генерирующий исключение. - person DevinB; 12.03.2009
comment
Я с leppie: может случиться так, что вы попытаетесь преобразовать строку, но проверьте отражатель для преобразования других типов, а также double, long, object и т. Д. - person Joel Coehoorn; 12.03.2009
comment
@devinb: НЕТ, НЕТ, НЕТ, TryParse НЕ использует внутренний try / catch. - person Joel Coehoorn; 12.03.2009
comment
В продолжение: int.Parse на самом деле вызывает int.TryParse сейчас и выдает исключение, если TryParse () терпит неудачу! stackoverflow.com/questions/467613/parse-v-tryparse - person Joel Coehoorn; 12.03.2009
comment
@GateKiller Я просто проверяю IL и (int), просто выполняю распаковку, а Convert.Int32 делает другие вещи (например, сначала вызывает GetobjectValue) - person dr. evil; 12.03.2009
comment
@ Джоэл: Мне пришлось ущипнуть себя, чтобы убедиться, что он действительно это сказал. Это полностью свело бы на нет цель TryParses. - person Samuel; 12.03.2009
comment
НЕТ! TryParse и Parse реализуются FROM SCRATCH, Parse не является TryParse за исключением внутреннего использования. и (int) 1 действительно не работает. - person nothrow; 12.03.2009