如何加速这个从字符串中删除文本的方法?

6
我写了下面这个方法来删除字符串中括号内的命名空间。
我希望尽可能地让它运行得更有什么方法可以加速以下代码吗?
using System;

namespace TestRemoveFast
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] tests = {
            "{http://company.com/Services/Types}ModifiedAt",
            "{http://company.com/Services/Types}CreatedAt"
                             };

            foreach (var test in tests)
            {
                Console.WriteLine(Clean(test));
            }

            Console.ReadLine();
        }

        static string Clean(string line)
        {
            int pos = line.IndexOf('}');
            if (pos > 0)
                return line.Substring(pos + 1, line.Length - pos - 1);
            else
                return line;
        }
    }
}

1
以下哪一种更快?line.Substring(pos + 1) 和 line.Substring(pos + 1, line.Length - pos - 1)。我想你之前测试过,选择了后者吧? - user159088
3
这并不慢。在我个人看来,添加正则表达式将是不必要的开销。 - user114600
你可以将pos+1移动到一个变量中,并将其用于起始位置和减法。但我们在讨论纳秒的问题;)不过这样可以避免执行+1和-1操作。同样适用于纳秒级别。将line.IndexOf('}')更改为line.IndexOf('}',8,line.Length)。这样可以节省一次方法调用和扫描起始字节。 - Mikael Svenson
11个回答

3

如果您不需要同步处理,可以尝试并行处理。使用PLINQ的并行foreach即可解决问题。

但是,如果您无法等待VS2010正式发布,可以尝试Emre Aydinceren的Poor Man's Parallel.ForEach Iterator


3

这种方法似乎相当快速。但从您提供的字符串中,我得出结论:名称通常比{URL}更小。您可以使用.LastIndexOf()方法。我认为它从字符串末尾开始。


我尝试了使用LastIndexOf结合Remove,得到了一些百分比的提升,但只有当定界符靠近输入字符串的末尾时才有效。当我将其移到开头时,速度又变慢了。当然,如果实际数据总是符合这个限制,那么操作者可以利用它。 - Bob Moore

2

假设你在这里找到了答案。我认为你需要考虑下一个查看你代码的人会看到什么样的“解决方案”。

相比几毫秒的时间,我更愿意选择可读性更强的代码。


除非你需要每秒处理几百万条记录。 - Matthew Whited
1
@Matthew Whited:给定的代码在我的可怜笔记本电脑上(http://ark.intel.com/Product.aspx?id=29761)成功处理了1,000,000个字符串,用时0.0875438秒,这意味着它可以在一秒钟内处理11,422,853个字符串。因此,每秒处理数超过几百万。 - jason

1
你尝试过使用正则表达式和/或使用 StringBuilder 而不是 String 吗?

1
如果你把速度换成空间,你可以在给定的数组中循环一次,并复制除了'{.*}'之外的字符。这将节省两个调用(.IndexOf()和.Substring())。

1

你确定这是你代码的瓶颈吗?你对该方法的时间要求有什么规定吗?你是否已经对现有的代码进行了剖析,以查看是否符合这些规格?

我猜你现有的代码几乎是最优的。无论是IndexOf还是Substring都会调用unsafe代码来执行各种花式优化,除非你也走unsafe路线,否则这些优化对你来说是不可用的。如果你这样做,你最终会重新编写IndexOfSubstring

因此,除非这段代码明确成为你代码的瓶颈,并且你对该方法的时间要求有合理规定,否则我建议把你的精力集中在其他方面。


0

其中最慢的是Console.WriteLine()。看下面的例子:

    public void TestCleanSpeed()
    {
        var start = DateTime.Now;
        for (var i = 0; i < 10000; i++)
        {
            string[] tests = {
                                 "{http://company.com/Services/Types}ModifiedAt",
                                 "{http://company.com/Services/Types}CreatedAt"
                             };

            foreach (var test in tests)
            {
                Console.WriteLine(Clean(test));
            }
        }
        var end = DateTime.Now;

        var ts = end - start;
        Console.WriteLine(ts);
    }

如果按原样运行,它需要近六秒钟的时间。然后,删除Console.WriteLine并改为赋值var newTest = Clean(test);。在我的测试中,10000次执行只需要不到0.02秒。


Console.WriteLine 是无关紧要的。它甚至不是他所询问的 Clean 方法的一部分。 - jason
for循环(var i = 0 ...)也没有关系。我猜测试的字符串数组可能很大。你描述了完全不同的情景。 - Johannes
@Jason - 我读到了“有没有办法加快下面的代码?”并且我理解为他指的是他发布的所有代码。我想我误解了。 - Matt Grande
@Johannes - 我加入了一个for循环,这样它就可以运行多次。当它只运行一次时,它没有记录执行的次数。 - Matt Grande

0
您可以将字符串转换为XName,并按以下方式获取名称部分。
((System.Xml.Linq.XName)"{http://company.com/Services/Types}ModifiedAt").LocalName

1
有趣的是,也许可以在其他地方使用,但在这个例子中它会使速度变慢大约3倍。 - Edward Tanguay

0

唯一的其他方法是使用line.Remove(0, pos + 1);,但我认为内部使用Remove比Substring更复杂,因为Remove还可以从中间切割一些内容。

因此,Substring()应该是最快的。


0
line.Substring(line.IndexOf('}') + 1);

略微更快。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接