在where子句内调用扩展方法时的C#LINQ性能

在where子句内调用扩展方法时的C#LINQ性能,c#,performance,linq,C#,Performance,Linq,我有一个像这样的LINQ查询 public static bool CheckIdExists(int searchId) { return itemCollection.Any(item => item.Id.Equals(searchId.ConvertToString())); } item.Id是一个字符串,而searchId是一个int.ConvertToString()是一个扩展,它将int转换为string ConvertToString的代码: public sta

我有一个像这样的LINQ查询

public static bool CheckIdExists(int searchId)
{
   return itemCollection.Any(item => item.Id.Equals(searchId.ConvertToString()));
}
item.Id
是一个
字符串
,而
searchId
是一个
int
.ConvertToString()
是一个扩展,它将
int
转换为
string

ConvertToString的代码:

public static string ConvertToString(this object input)
{
   return Convert.ToString(input, CultureInfo.InvariantCulture);
}
现在我的查询是,是否对
itemCollection
中的每个项目执行
searchId.ConvertToString()

public static bool CheckIdExists(int searchId)
{
   string sId=searchId.ConvertToString();
   return itemCollection.Any(item => item.Id.Equals(sId));
}
正在预先计算
searchId.ConvertToString()
并调用下面的方法以提高性能?

public static bool CheckIdExists(int searchId)
{
   string sId=searchId.ConvertToString();
   return itemCollection.Any(item => item.Id.Equals(sId));
}

如何调试这两个场景并观察它们的性能?

最终指南是需要多长时间。您可以创建秒表来记录任何代码的性能。只需使用ElapsedMills来查看花费了多长时间。对于非常短的操作,我建议使用非常长的循环来获得更精确的时间长度

public static bool CheckIdExists(int searchId)
{
   string sId=searchId.ConvertToString();
   return itemCollection.Any(item => item.Id.Equals(sId));
}
var watch = new Stopwatch();
watch.Start();
/// CODE HERE (IDEALLY IN A LONG LOOP)
Debub.WriteLine($"Took {watch.ElapsedMilliseconds}");

它需要多长时间才是最终的指南。您可以创建秒表来记录任何代码的性能。只需使用ElapsedMills来查看花费了多长时间。对于非常短的操作,我建议使用非常长的循环来获得更精确的时间长度

var watch = new Stopwatch();
watch.Start();
/// CODE HERE (IDEALLY IN A LONG LOOP)
Debub.WriteLine($"Took {watch.ElapsedMilliseconds}");

我重新生成了您在问题中提到的场景。我尝试了以下代码并得到了这个输出

但这就是调试的方法

static List<string> itemCollection = new List<string>();

static void Main(string[] args)
{

    for (int i = 0; i < 10000000; i++)
    {
        itemCollection.Add(i.ToString());
    }

    var watch = new Stopwatch();
    watch.Start();

    Console.WriteLine(CheckIdExists(580748));
    watch.Stop();
    Console.WriteLine($"Took {watch.ElapsedMilliseconds}");

    var watch1 = new Stopwatch();
    watch1.Start();

    Console.WriteLine(CheckIdExists1(580748));
    watch1.Stop();
    Console.WriteLine($"Took {watch1.ElapsedMilliseconds}");

    Console.ReadLine();
}

public static bool CheckIdExists(int searchId)
{
    return itemCollection.Any(item => item.Equals(ConvertToString(searchId)));
}

public static bool CheckIdExists1(int searchId)
{
    string sId =ConvertToString(searchId);

    return itemCollection.Any(item => item.Equals(sId));
}

public static string ConvertToString(int input)
{
    return Convert.ToString(input, CultureInfo.InvariantCulture);
}

我重新生成了您在问题中提到的场景。我尝试了以下代码并得到了这个输出

但这就是调试的方法

static List<string> itemCollection = new List<string>();

static void Main(string[] args)
{

    for (int i = 0; i < 10000000; i++)
    {
        itemCollection.Add(i.ToString());
    }

    var watch = new Stopwatch();
    watch.Start();

    Console.WriteLine(CheckIdExists(580748));
    watch.Stop();
    Console.WriteLine($"Took {watch.ElapsedMilliseconds}");

    var watch1 = new Stopwatch();
    watch1.Start();

    Console.WriteLine(CheckIdExists1(580748));
    watch1.Stop();
    Console.WriteLine($"Took {watch1.ElapsedMilliseconds}");

    Console.ReadLine();
}

public static bool CheckIdExists(int searchId)
{
    return itemCollection.Any(item => item.Equals(ConvertToString(searchId)));
}

public static bool CheckIdExists1(int searchId)
{
    string sId =ConvertToString(searchId);

    return itemCollection.Any(item => item.Equals(sId));
}

public static string ConvertToString(int input)
{
    return Convert.ToString(input, CultureInfo.InvariantCulture);
}

是的,一次获取字符串应该更快。但我猜编译器确实为您优化了它(我只是怀疑这一点,没有任何东西可以备份它。我只是记得编译器非常擅长检测不变的东西)

不,它不是为每个项目计算的,因为LINQ方法Any不一定检查所有项目。对于第一个匹配项,它返回true。当它检查所有项目时,唯一的场景是lambda返回true

如果要测试速度差,请确保有更多数据,否则差异可能太小

只要做:

itemCollection=Enumerable.Range(0,1000)。选择many(x=>itemCollection)。ToList()//或数组或任何您拥有的集合类型


而不是用秒表测量时间,就像@RobSedgwick说的那样

是的,一次得到字符串应该更快。但我猜编译器确实为您优化了它(我只是怀疑这一点,没有任何东西可以备份它。我只是记得编译器非常擅长检测不变的东西)

不,它不是为每个项目计算的,因为LINQ方法Any不一定检查所有项目。对于第一个匹配项,它返回true。当它检查所有项目时,唯一的场景是lambda返回true

如果要测试速度差,请确保有更多数据,否则差异可能太小

只要做:

itemCollection=Enumerable.Range(0,1000)。选择many(x=>itemCollection)。ToList()//或数组或任何您拥有的集合类型


而不是用秒表测量时间,就像@RobSedgwick说的那样

我想你有两个解决方案:

1-在此日志日期时间内创建日志和meke。现在
2-您可以使用诊断工具选项卡


希望这对您有所帮助

我认为您有两种解决方案:

1-在此日志日期时间内创建日志和meke。现在
2-您可以使用诊断工具选项卡


希望这能帮助您

“如何调试这两个场景”-好吧,把
控制台.WriteLine(“我被调用!”)
放在
转换字符串
中,观察它在您的场景中被调用的频率。@evk是诚实的,另一件事是在其上放置秒表并计时。将尝试
控制台。WriteLine
方法只需在ConvertToString方法中设置一个断点,然后查看到达该断点的次数。基本的debugging@RaduUngureanu我试过了,每次在ConvertToSTring中都会出现。。但是,如果不进行调试,它的工作方式会有所不同。。我知道。。愚蠢的假设“如何调试这两个场景”-好吧,把
控制台.WriteLine(“我被调用!”)
放在
ConvertToString
中,观察它在您的场景中被调用的频率。@evk是诚实的,另一件事是在其上放置秒表并计时。将尝试
控制台。WriteLine
方法只需在ConvertToString方法中设置一个断点,然后查看到达该断点的次数。基本的debugging@RaduUngureanu我试过了,每次在ConvertToSTring中都会出现。。但是,如果不进行调试,它的工作方式会有所不同。。我知道。。愚蠢的假设让秒表慢了几百万秒会停止吗?watch.stop()会这样做。我相信,当你调用elapsedmillisons时,手表仍在滴答作响。获取elapsedmillisons会停止秒表吗?watch.stop()会这样做。我相信当你打电话给ElapsedMills的时候,手表还在滴答作响。我试着根据Rob的回答来写,最后得到了你的密码。。。看起来预先计算会提供更好的性能您可以更改整数以生成不同的结果。对于较大的数字,第一种方法将根据Rob的答案进行长时间的尝试编写,并以您的代码结束。。。看起来预先计算会提供更好的性能您可以更改整数以生成不同的结果。对于较大的数字,第一种方法将花费较长的时间