我应该推出自己的ParseInt32版本吗?

时间:2009-01-06 11:30:58

标签: .net performance parsing

我正在编写一个高性能解析器,在我看来Int32.Parse可能太慢了。我写了一个假设正确输入的简单版本,它表现得更好。那么我应该创建自己的版本吗?或者还有另一种更快的方法吗?

我的方法是这样的:

// parse simple int, assuming relatively correct input (i.e. all digits)
public static int ParseInt32Simply(string str) {
    if (str == null) throw new ArgumentNullException("str");
    if (str.Length == 0) throw new ArgumentException("str is empty");

    int sign = 1, index = 0;
    if (str[0] == '-') { sign = -1; index = 1; }
    else if (str[0] == '+') { index = 1; }

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

    if (result < 0) throw new OverflowException(str + " is too large for Int32");

    return result * sign;
}

我的结果与内置的等价物非常不同:

Int32.Parse      took 8.2775453 seconds
ParseInt32Simply took 0.6511523 seconds
Int32.Parse      took 6.7625807 seconds
ParseInt32Simply took 0.4677390 seconds

(在我的机器上运行2500万次迭代;运行VS 2008 SP1的P4 3 GHz)

那么,我应该使用我的版本吗?或者我可以使用另一种方法吗?

11 个答案:

答案 0 :(得分:6)

您是否已分析过您的代码以确定ParseInt32实际上是瓶颈?除非你肯定知道你会看到一个好处,否则我不会替换你正在编码的环境的“标准库”的一部分。

答案 1 :(得分:5)

.net Int32.Parse非常非常快速成功。

当它失败时会引发异常 - 然后它非常慢,因为异常很慢。

你需要扩展你的测试 - 你需要检查一下好的和坏的字符串模式的时间,这类似于你需要它做的。

如果您非常确定所有字符串都是有效的整数,则Int32.Parse是可行的方法。如果您怀疑只有极少数可以忽略不计,那么在循环中使用Int32.TryParse而不是try-catch要快得多。

通常情况下,如果您的try-catch位于循环之外,请使用Int32.Parse - 您将获得异常并在第一次获得无效值时停止。

如果您的try-catch位于循环内,请使用Int32.TryParse

Int32.ParseInt32.TryParse都经过高度优化并且相对成熟 - 除非您有专业情况,否则我认为它们很难改进。

答案 2 :(得分:4)

我的观点是,如果节省的时间对您的应用程序而言意义重大并且有益,那就去吧。

我们在XML解析方面存在一个模糊的类似问题,并且出于性能原因选择手动执行,但它基于已知的环境 - 我们正在提供XML,因此我们可以相当安全地在解析中使用快捷方式。

显然风险在于它不太可能像标准库版本那样完整,因此需要让团队的新开发人员意识到这一点,以免他们做些什么来打破它。

答案 3 :(得分:4)

是的 - 您可以使用自己的解析int版本,只要您100%确定源数据是您可以控制的(因此始终符合您的Int32格式)。此外,您应该使用自己的代码来隔离世界其他地方,因为如果您在某个库中发布了这个代码,那么人们可能希望拥有Int32.Parse的标准行为。如果你不能提供,那对他们没有好处。然而,正如这里的许多人所暗示的那样,如果你试图挤出你的大部分表现,你应该确定这是真正需要做的事情。但是,您可能比这里的任何人都更了解自己的代码。

我个人会尝试避免更改解析。如果还有其他瓶颈,那么首先可能需要进行调查。

答案 4 :(得分:4)

如果您的测试是可验证的,并且您确实需要性能提升(例如,您将该函数调用为每秒数万次),那么就不需要了。

我只是更改名称...因为 ParseInt32Simply 没有告诉维护程序员什么。我认为像 TrustedSourceInt32Parse GuaranteedInt32Parse 之类的名称或其他类似的名称是更好的名称。

答案 5 :(得分:3)

我认为这里的主要问题是你的句子假定正确的输入。从阅读代码开始,它似乎无法正确处理“12x”。

Int32.Parse有很多东西可以验证输入,甚至可以记录你的文化来处理一些文化差异,虽然我不能想到任何专门用于Int32的东西。

您确定代码中的瓶颈是Int32吗?

答案 6 :(得分:1)

你如何衡量速度?我试过这个:

Stopwatch sw = new Stopwatch();
Random rand = new Random();

for (int n = 0; n < 10; n++)
{
    sw.Start();
    for (int i = 0; i < 1000000; i++)
    {
        ParseInt32Simply(rand.Next().ToString());
    }
    sw.Stop();
    Console.WriteLine(sw.Elapsed.Ticks + " - ParseInt32Simply");
    sw.Reset();

    sw.Start();
    for (int i = 0; i < 1000000; i++)
    {
        int.Parse(rand.Next().ToString());
    }
    sw.Stop();
    Console.WriteLine(sw.Elapsed.Ticks + " - int.Parse");
    sw.Reset();
    Console.WriteLine();
}

结果完全不同:

2932852 - ParseInt32Simply
4684522 - int.Parse

3003988 - ParseInt32Simply
4666928 - int.Parse

2892545 - ParseInt32Simply
4660209 - int.Parse

2888998 - ParseInt32Simply
4636007 - int.Parse

2955727 - ParseInt32Simply
4668501 - int.Parse

2929210 - ParseInt32Simply
4653799 - int.Parse

2893706 - ParseInt32Simply
4671503 - int.Parse

2899547 - ParseInt32Simply
4633957 - int.Parse

你的简单方法仍然更快,但不到2倍(实际上这是非常好的表现!)。

答案 7 :(得分:1)

如果您解析的格式是您知道的有效数字,那么您确实可以编写更快的自定义解析器。我曾为同一目的写过一个Double.Parse函数。从最低有效数字开始更快。这样你就可以增加解析数字的功效。

我已经创建了这个的快速实现,

public static Int32 ParseValidNumberAsInt32(string str)
{
    if (str == null) 
        throw new ArgumentNullException("str");
    if (str.Length == 0) 
        throw new ArgumentException("str is empty");
    Int32 result = 0;
    Int32 currentPower = 1;
    Boolean isNegative = str[0] == '-';

    for (int currentCharIndex = str.Length - 1; currentCharIndex > 0; currentCharIndex--)
    {
        result += (str[currentCharIndex] - '0') * currentPower;
        currentPower *= 10;
    }
    return isNegative ? -1 * result : result + ((str[0] - '0') * currentPower);
}

如果你真的想要速度,你可以写一个不安全的实现..

如果您解析一个大文件,您可以将文件作为原始字节读取并使用它们。这将使它快得多(不转换为unicode字符串,不在行中拆分字符串,不在子字符串中拆分行,不解析子字符串),但是你将失去可维护性。

答案 8 :(得分:1)

请查看此博客文章:Karl Seguin撰写的Fast string to integer conversion

答案 9 :(得分:0)

对null和空字符串的验证是不够的,你应该检查参数是否是有效的整数。

答案 10 :(得分:0)

您的测试结果如何? 看来你的测试还不行。

当我循环50000次时,我只有一点点差别 然后我有大约30K的差异,有利于你的自定义方法, 但这对于普通方法的优点是可以忽略的