【问题标题】:Performance with LINQ on a string在字符串上使用 LINQ 的性能
【发布时间】:2016-11-16 12:38:54
【问题描述】:

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

这是我的代码:

    [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 快。根据测试资源管理器。

TestMethod1 = 2ms 测试方法2 =

如果我尝试在每个测试中添加秒表,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 = 7ms

谢谢大家的回复

【问题讨论】:

  • 创建一个从 1 到 10000 的循环,在它们之间用秒表执行它们,看看哪个更快。
  • 这样比较它们似乎不公平,因为这两种方法不一样,比如给定输入如“10 20 (30)”,那么第一个将返回“30”,但第二个将返回“102030”。
  • 第一种方法搜索括号。第二种方法搜索数字。您正在将苹果与 tomaccos 进行比较。
  • 它运行的第一个测试(IDE 中的 MS 测试)与第二个相比似乎总是有一些开销。正如其他人所说,您的测试根本不会测量相同类型的操作,您应该在循环中测量两者的时间,以使随机外部因素的影响更小。
  • @Sasquatch 你不能依赖任何一个,因为整个测试都是错误的。使用 BenchmarkDotNet 之类的工具多次重复相同的测试并收集重要指标,例如持续时间、RAM、分配、GC 成本。就个人而言,我会使用正则表达式。它既简单又快捷

标签: c# linq performance-testing


【解决方案1】:

我同意大多数 cmets 的观点,我认为在没有单元测试的情况下进行测试可能会有所帮助。如果您使用 LINQ,请使用 LINQPad(免费标准版)运行此类测试或其他小代码块。以下是测试,也扩展到包括 Regex,并增加到 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 

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 2017-05-18
    • 2014-04-01
    相关资源
    最近更新 更多