在开发我的应用程序时,我遇到了一些比较的东西:
string str = "12345";
int j = 12345;
if (str == j.ToString())
{
//do my logic
}
我在想以上的事情也可以用:
string str = "12345";
int j = 12345;
if (Convert.ToInt32(str) == j)
{
//do my logic
}
所以我开发了一个示例代码来测试性能哪个更好
var iterationCount = 1000000;
var watch = new Stopwatch();
watch.Start();
string str = "12345";
int j = 12345;
for (var i = 0; i < iterationCount; i++)
{
if (str == j.ToString())
{
//do my logic
}
}
watch.Stop();
第二个:
var iterationCount = 1000000;
var watch = new Stopwatch();
watch.Start();
string str = "12345";
int j = 12345;
for (var i = 0; i < iterationCount; i++)
{
if (Convert.ToInt32(str) == j)
{
//do my logic
}
}
watch.Stop();
在进行上述两项测试后,我发现上述测试的时间几乎相同。我想讨论哪一个更好的方法?还有其他方法比两个以上的方法更好吗?
答案 0 :(得分:16)
您的测试存在根本缺陷。编译器和运行时非常聪明,并且会在编译时和运行时优化代码(JIT-ing)。在这种情况下,您每次都会执行相同的操作,这将由编译器发现并进行优化,因此每种方法的时序都相似。
试试这个版本(我只有.Net 2.0,因此稍有变化):
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace ToStringTest
{
class Program
{
const int
iterationCount = 1000000;
static TimeSpan Test1()
{
Stopwatch watch = new Stopwatch();
watch.Start();
string str = "12345";
int j = 12345;
for (int i = 0; i < iterationCount; i++)
{
if (str == i.ToString())
{
//do my logic
}
}
watch.Stop();
return watch.Elapsed;
}
static TimeSpan Test2()
{
Stopwatch watch = new Stopwatch();
watch.Start();
string str = "12345";
int j = 12345;
for (int i = 0; i < iterationCount; i++)
{
if (Convert.ToInt32(i) == j)
{
//do my logic
}
}
watch.Stop();
return watch.Elapsed;
}
static void Main(string[] args)
{
Console.WriteLine("ToString = " + Test1().TotalMilliseconds);
Console.WriteLine("Convert = " + Test2().TotalMilliseconds);
}
}
}
你将看到巨大的差异。一个比另一个快两个数量级。它真的是显而易见的。
您需要知道各种操作正在做什么才能知道哪些操作从根本上更快。
将字符串转换为int需要以下内容:
total = 0
for each character in string
total = total * 10 + value of charater
并且ToString需要:
string = ""
while value != 0
string.AddToFront value % 10
value /= 10
对于CPU而言,乘法比分割更容易,更快。考虑到选择具有大量乘法的算法与具有大量除法的算法,总是选择前者,因为它总是更快。
然后进行比较,int-int比较很简单,将每个值加载到寄存器中并进行比较 - 几个机器指令就完成了。两个字符串之间的比较需要一次一个地测试字符串中的每个字符 - 在您给出的示例中,它是5个字节(int可能是4个字节),这是更多的内存访问。
答案 1 :(得分:13)
嗯 - 表现不应该是唯一重要的事情。
您应该询问是要比较实际值还是仅比较数字的表示。
采用以下示例: “00001”是否等于1?如果您希望它使用Int.TryParse组合将字符串转换为int,然后比较它们。
根据本地设置,可能还有其他差异。也许用户已设置格式化为“1,000,000” - 如果您将该字符串与1000000.ToString()进行比较,结果将为false。
答案 2 :(得分:6)
我更喜欢i.ToString() == str
,因为没有任何保证Convert.ToInt32(str)
不会失败。
答案 3 :(得分:3)
Yikes,您将域逻辑显示为在分析循环中,因此您没有测试代码的Convert
和ToString
版本之间的时差;您正在测试转换的合并时间以及业务逻辑的执行情况。如果您的业务逻辑很慢并占据转换时间,那么您当然会在每个版本中看到相同的时间。
现在,尽管如此,在您知道这是一个性能瓶颈之前,即使担心这一点,也需要过早优化。特别是,如果执行域逻辑控制转换时间,则两者之间的差异永远不会重要。所以,选择最具可读性的那个。
现在,关于使用哪个版本:您需要首先准确指定您正在测试的内容。你有什么投入? “007”是否会成为输入? “007”与整数7不同吗? “1,024”是否会成为输入?是否存在本地化问题?
答案 4 :(得分:2)
如果性能几乎相同,请使用更具可读性的版本。
就个人而言,我发现.ToString()
方法更容易理解,而且更不容易出现另一种方法可能出现的问题。
答案 5 :(得分:2)
语义有点不同。 "01" == 1.ToString()
false ,1 == Convert.ToInt32("01")
true 。
如果解析可能出错(字符串不是有效数字),那么Int32.TryParse
比使用Convert.ToInt32()
更快。
答案 6 :(得分:0)
对于初学者来说,将int转换为字符串的第一个如果与int进行比较的字符串不能转换为int,则不会抛出错误。
如果您在批量转换为字符串时进行了大量测试,则会因转换错误而消除可能导致异常抛出的问题。提高异常需要时间并且会减慢第二次测试的速度。
答案 7 :(得分:0)
好的,我进一步提前一步并以这种方式进行测试:
int j = 123;
for (var i = 0; i < iterationCount; i++)
{
j.ToString();
}
第二个: string str =“123”;
for (var i = 0; i < iterationCount; i++)
{
Convert.ToInt32(str);
}
在这种情况下,我发现每次第二次表现都好一点。在我的情况下,数字仅为100000,而不是100,000。你对这个测试的评论我在这篇文章中做了什么?