【问题标题】:Any more efficient method of converting a string integer to int than convert.toint32将字符串整数转换为 int 比 convert.toint32 更有效的方法
【发布时间】:2016-09-21 10:15:21
【问题描述】:

有没有比在c#中使用Convert.ToInt32()更有效的方法将字符串整数转换为int?

我有一个程序可以将很多字符串转换为整数。这些值是从字符串格式的文本文件中读取的。

【问题讨论】:

  • 你试过Int.Parse()吗?
  • 目前有多快,您需要多快? (我个人会使用int.Parseint.TryParse,但差别不大。)
  • 你的字符串长度有限制吗?
  • @Douglas 是的,最多 1000 万
  • @Jay:如果你不知道它是否足够快,那么你就专注于错误的事情。尽可能简单易读地编写代码以使其正常工作,然后测试性能并查看它是否足够好。

标签: c#


【解决方案1】:

不,可能不会,至少目前还不会。我尝试了这个快速而肮脏的基准测试:

private static int toint(string s) {
    int res = 0;
    foreach (var c in s) {
        res = 10*res + (c - '0');
    }
    return res;
}

static void Main() {
    var s = DateTime.Now;
    for (int i = 0 ; i != 10000000 ; i++) {
        if (Convert.ToInt32("112345678") == 0) break;
    }
    var m = DateTime.Now;
    for (int i = 0; i != 10000000; i++) {
        if (toint("112345678") == 0) break;
    }
    Console.WriteLine("{0} {1}", DateTime.Now-m, m-s);
}

我的 toint 方法跳过了各种验证,得到的结果仅比 Convert.ToInt32 提高了 40%:1.14 秒与 1.86 秒。

只为脏toint添加一个基本验证几乎完全消除了它的优势:这种方法

private static int toint(string s) {
    int res = 0;
    foreach (var c in s) {
        if (Char.IsDigit(c))
            res = 10*res + (c - '0');
    }
    return res;
}

在 1.62 秒内运行,或提高 13%同时保持基本不正确

【讨论】:

  • 如果这发生在内部循环中,40% 可能是一个非常显着的改进。
  • @EricJ。当然,如果您可以免费获得它,40% 就很棒了。但是,在这种情况下,您可以通过引入可能不正确的行为来换取它,这可能会或可能不会被接受,具体取决于具体情况。
【解决方案2】:

使用这种方法:

    private static int Parse(string s)
    {
        int value = 0;
        for (var i = 0; i < s.Length; i++)
        {
            value = value*10 + (s[i] - '0');
        }
        return value;
    }

我得到 750 毫秒,而不是 18+ 秒int.Parse 获得 1 亿次转化。

除非这是您真正的瓶颈并且您不关心任何形式的验证,否则我不会推荐它。

【讨论】:

    【解决方案3】:

    如果您从 Stream 读取整数,则可以通过避免初始化字符串的开销来优化。

    例如,假设您的数字始终为非负数并以, 字符结尾,您可以使用:

    int num = stream.ReadByte() - '0';
    byte next = (byte)stream.ReadByte();
    while (next != ',')
    {
        num = num * 10 + next - '0';
        next = (byte)stream.ReadByte();
    }
    

    【讨论】:

      【解决方案4】:

      This page 对 4 种技术进行基准测试。最快的方法是 Romain 在上面写的:

      y = 0;
      for (int i = 0; i < s[x].Length; i++)
          y = y * 10 + (s[x][i] - '0');
      

      这里有一些 other methods that were tested 被证明慢了将近 10 倍(其中“s”是作者用于转换的字符串数组):

      int.Parse(s[x]);
      Int32.TryParse(s[x], out y);
      Convert.ToInt32(s[x]);
      

      【讨论】:

        【解决方案5】:

        Convert.ToInt32() 使用Int32.Parse()(加入了一点验证)。 Int32.Parse() 反过来使用Number.Parse()

        除非您对输入值有重要了解(例如,您的输入始终是固定位数,它永远不是十六进制,具有一定的精度,它始终是无符号的,等等)

        private unsafe static Boolean NumberToInt64(ref NumberBuffer number, ref Int64 value) {
        
            Int32 i = number.scale;
            if (i > Int64Precision || i < number.precision) {
                return false;
            }
            char* p = number.digits;
            BCLDebug.Assert(p != null, "");
            Int64 n = 0;
            while (--i >= 0) {
                if ((UInt64)n > (0x7FFFFFFFFFFFFFFF / 10)) {
                    return false;
                }
                n *= 10;
                if (*p != '\0') {
                    n += (Int32)(*p++ - '0');
                }
            }
            if (number.sign) {
                n = -n;
                if (n > 0) {
                    return false;
                }
            }
            else {
                if (n < 0) {
                    return false;
                }
            }
            value = n;
            return true;
        }
        

        我在我自己的基础框架和分析器会话中广泛使用 Convert.ToXYZ() 方法,即使在单个操作中调用数百次(例如反序列化复杂对象树),它们也只是微不足道的开销。

        我遇到过可以使用专门算法提高 BCL 性能的地方,但这可能不是其中之一。

        【讨论】:

          猜你喜欢
          • 2013-05-25
          • 2012-07-26
          • 2012-11-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-31
          相关资源
          最近更新 更多