在字符串上使用 LINQ 的性能

Performance with LINQ on a string

我进行了两次测试,因为我想测试在尝试在字符串中查找数字的两种不同实现方式上的性能。

这是我的代码:

    [TestMethod]
    public void TestMethod1()
    {
        string text = "I want to find the number (30)";
        var startNumber = text.IndexOf('(');
        var trimmed = text.Trim(')');
        var number = trimmed.Substring(startNumber).Trim('(');

        Assert.AreEqual("30", number);
    }

    [TestMethod]
    public void TestMethod2()
    {
        string text = "I want to find the number (30)";
        var lambdaNumber = text.Where(x => Char.IsNumber(x)).ToArray();
        var joined = string.Join("", lambdaNumber);

        Assert.AreEqual("30", joined);
    }

结果是 TestMethod2(使用 lamda 表达式)比 TestMethod1 快。根据测试浏览器。

测试方法 1 = 2 毫秒 测试方法 2 = <1 毫秒

如果我尝试在每个测试中添加秒表,TestMethod1 是迄今为止最快的。

如何正确测试此行为的性能?

编辑:

我很欣赏这些方法不执行相同的操作。因此我改为创建了以下内容:

    [TestMethod]
    public void TestMethod1()
    {
        var sw = new Stopwatch();
        sw.Start();

        var number = string.Empty;
        var counter = 0;
        while (counter < 100000)
        {
            number = string.Empty;
            string text = "I want to find the number (30)";
            foreach (var c in text.ToCharArray())
            {
                int outNumber;
                if (int.TryParse(c.ToString(), out outNumber))
                    number += c.ToString();
            }
            counter++;
        }

        sw.Stop();

        Assert.AreEqual("30", number);
    }

    [TestMethod]
    public void TestMethod2()
    {
        var sw = new Stopwatch();
        sw.Start();

        var joined = String.Empty;
        var counter = 0;
        while (counter < 100000)
        {
            string text = "I want to find the number (30)";
            var lambdaNumber = text.Where(x => Char.IsNumber(x)).ToArray();
            joined = string.Join("", lambdaNumber);
            counter++;
        }

        sw.Stop();

        Assert.AreEqual("30", joined);
    }

根据秒表,结果如下: 测试方法 1 = 19 毫秒 测试方法 2 = 7 毫秒

谢谢大家的回复

因为我同意大多数评论,所以我认为在没有单元测试的情况下进行测试可能会有所帮助。如果您使用 LINQ,请使用 LINQPad(免费标准版)来 运行 像这样或其他小代码块进行测试。这里是测试,扩展到包括正则表达式,并增加到 100000 个循环。

void Main()
{
    string text = "I want to find the number (30)";

    Stopwatch sw = Stopwatch.StartNew();

    for (int i = 0; i < 100000; i++)
    {
        TestMethod1();
    }

    sw.Elapsed.TotalMilliseconds.Dump("Substring no parameter");    
    sw = Stopwatch.StartNew();

    for (int i = 0; i < 100000; i++)
    {
        TestMethod1(text);
    }

    sw.Elapsed.TotalMilliseconds.Dump("Substring parameter");
    sw = Stopwatch.StartNew();

    for (int i = 0; i < 100000; i++)
    {
        TestMethod2();
    }

    sw.Elapsed.TotalMilliseconds.Dump("LINQ no parameter");
    sw = Stopwatch.StartNew();

    for (int i = 0; i < 100000; i++)
    {
        TestMethod2(text);
    }

    sw.Elapsed.TotalMilliseconds.Dump("LINQ parameter");
    sw = Stopwatch.StartNew();

    for (int i = 0; i < 100000; i++)
    {
        TestMethod3(text);
    }

    sw.Elapsed.TotalMilliseconds.Dump("Regex In");
    sw = Stopwatch.StartNew();

    for (int i = 0; i < 100000; i++)
    {
        TestMethod4(text);
    }

    sw.Elapsed.TotalMilliseconds.Dump("Regex Out");
    sw = Stopwatch.StartNew();
    sw.Stop();
}

// Define other methods and classes here
public void TestMethod1()
{   
    string text = "I want to find the number (30)";
    var startNumber = text.IndexOf('(');
    var trimmed = text.Trim(')');
    var number = trimmed.Substring(startNumber).Trim('(');
}

public void TestMethod1(string text)
{
    var startNumber = text.IndexOf('(');
    var trimmed = text.Trim(')');
    var number = trimmed.Substring(startNumber).Trim('(');
}

public void TestMethod2()
{
    string text = "I want to find the number (30)";
    var lambdaNumber = text.Where(x => Char.IsNumber(x)).ToArray();
    var joined = string.Join("", lambdaNumber);
}

public void TestMethod2(string text)
{   
    var lambdaNumber = text.Where(x => Char.IsNumber(x)).ToArray();
    var joined = string.Join("", lambdaNumber);
}

public void TestMethod3(string text)
{
    var regex = new Regex(@"(\d+)");
    var match = regex.Match(text);
    var joined = match.Captures[0].Value;
}

public Regex regex = new Regex(@"(\d+)");

public void TestMethod4(string text)
{
    var match = regex.Match(text);
    var joined = match.Captures[0].Value;
}

结果:

Substring no parameter
11.3526 

Substring parameter
10.2901 

LINQ no parameter
60.2359 

LINQ parameter
56.5218 

Regex In
301.1179 

Regex Out
89.8345 

结论?我们仍在将苹果与橙子与钻石进行比较。而且正则表达式似乎并不像某些人建议的那样快。专业工具是必经之路。