C# 解析性能(If、TryParse、Try-Catch)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/150114/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Parsing Performance (If, TryParse, Try-Catch)
提问by Brendan Enrick
I know plenty about the different ways of handling parsing text for information. For parsing integers for example, what kind of performance can be expected. I am wondering if anyone knows of any good stats on this. I am looking for some real numbers from someone who has tested this.
我非常了解处理信息解析文本的不同方法。例如,对于解析整数,可以预期什么样的性能。我想知道是否有人知道这方面的任何好的统计数据。我正在从测试过这个的人那里寻找一些真实的数字。
Which of these offers the best performance in which situations?
其中哪些在哪些情况下提供了最佳性能?
Parse(...) // Crash if the case is extremely rare .0001%
If (SomethingIsValid) // Check the value before parsing
Parse(...)
TryParse(...) // Using TryParse
try
{
Parse(...)
}
catch
{
// Catch any thrown exceptions
}
采纳答案by user7116
Always use T.TryParse(string str, out T value). Throwing exceptions is expensive and should be avoided if you can handle the situation a priori. Using a try-catch block to "save" on performance (because your invalid data rate is low) is an abuse of exception handling at the expense of maintainability and good coding practices. Follow sound software engineering development practices, write your test cases, run your application, THEN benchmark and optimize.
始终使用T.TryParse(string str, out T value)。抛出异常代价高昂,如果您可以先验地处理这种情况,就应该避免。使用 try-catch 块来“节省”性能(因为您的无效数据率很低)是对异常处理的滥用,以牺牲可维护性和良好的编码实践为代价。遵循完善的软件工程开发实践,编写测试用例,运行应用程序,然后进行基准测试和优化。
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%" -Donald Knuth
“我们应该忘记小效率,比如大约 97% 的时间:过早的优化是万恶之源。但我们不应该在关键的 3% 中放弃我们的机会”-Donald Knuth
Therefore you assign, arbitrarily like in carbon credits, that the performance of try-catch is worseand that the performance of TryParse is better. Only after we've run our application and determined that we have some sort of slowdown w.r.t. string parsing would we even consider using anything other than TryParse.
因此,您可以像在碳信用中那样任意指定 try-catch的性能更差,而 TryParse 的性能更好。只有在我们运行我们的应用程序并确定我们有某种减慢 wrt 字符串解析后,我们才会考虑使用除 TryParse 之外的任何其他内容。
(edit: since it appears the questioner wanted timing data to go with good advice, here is the timing data requested)
(编辑:由于提问者似乎希望时间数据与好的建议一起使用,这里是请求的时间数据)
Times for various failure rates on 10,000 inputs from the user (for the unbelievers):
来自用户的 10,000 次输入的各种故障率的时间(对于非信徒):
Failure Rate Try-Catch TryParse Slowdown
0% 00:00:00.0131758 00:00:00.0120421 0.1
10% 00:00:00.1540251 00:00:00.0087699 16.6
20% 00:00:00.2833266 00:00:00.0105229 25.9
30% 00:00:00.4462866 00:00:00.0091487 47.8
40% 00:00:00.6951060 00:00:00.0108980 62.8
50% 00:00:00.7567745 00:00:00.0087065 85.9
60% 00:00:00.7090449 00:00:00.0083365 84.1
70% 00:00:00.8179365 00:00:00.0088809 91.1
80% 00:00:00.9468898 00:00:00.0088562 105.9
90% 00:00:01.0411393 00:00:00.0081040 127.5
100% 00:00:01.1488157 00:00:00.0078877 144.6
/// <param name="errorRate">Rate of errors in user input</param>
/// <returns>Total time taken</returns>
public static TimeSpan TimeTryCatch(double errorRate, int seed, int count)
{
Stopwatch stopwatch = new Stopwatch();
Random random = new Random(seed);
string bad_prefix = @"X";
stopwatch.Start();
for(int ii = 0; ii < count; ++ii)
{
string input = random.Next().ToString();
if (random.NextDouble() < errorRate)
{
input = bad_prefix + input;
}
int value = 0;
try
{
value = Int32.Parse(input);
}
catch(FormatException)
{
value = -1; // we would do something here with a logger perhaps
}
}
stopwatch.Stop();
return stopwatch.Elapsed;
}
/// <param name="errorRate">Rate of errors in user input</param>
/// <returns>Total time taken</returns>
public static TimeSpan TimeTryParse(double errorRate, int seed, int count)
{
Stopwatch stopwatch = new Stopwatch();
Random random = new Random(seed);
string bad_prefix = @"X";
stopwatch.Start();
for(int ii = 0; ii < count; ++ii)
{
string input = random.Next().ToString();
if (random.NextDouble() < errorRate)
{
input = bad_prefix + input;
}
int value = 0;
if (!Int32.TryParse(input, out value))
{
value = -1; // we would do something here with a logger perhaps
}
}
stopwatch.Stop();
return stopwatch.Elapsed;
}
public static void TimeStringParse()
{
double errorRate = 0.1; // 10% of the time our users mess up
int count = 10000; // 10000 entries by a user
TimeSpan trycatch = TimeTryCatch(errorRate, 1, count);
TimeSpan tryparse = TimeTryParse(errorRate, 1, count);
Console.WriteLine("trycatch: {0}", trycatch);
Console.WriteLine("tryparse: {0}", tryparse);
}
回答by Patrick Desjardins
Try-Catch will always be the slower. TryParse will be faster.
Try-Catch 总是较慢。TryParse 会更快。
The IF and TryParse are the same.
IF 和 TryParse 是相同的。
回答by Kev
Although I haven't personally profiled the different ways, this chap has:
虽然我没有亲自介绍不同的方式,但这一章有:
回答by Chris Cudmore
Option 1: Will throw an exception on bad data.
Option 2: SomethingIsValid() could be quite expensive - particularly if you are pre-checking a string for Integer parsability.
Option 3: I like this. You need a null check afterwards, but it's pretty cheap.
Option 4 is definitely the worst.
Exception handling is comparatively expensive, so avoid it if you can.
异常处理相对昂贵,因此如果可以,请避免使用它。
In particular, bad inputs are to be expected, not exceptional, so you shouldn't use them for this situation.
特别是,错误的输入是可以预料的,不是例外,因此您不应该在这种情况下使用它们。
(Although, before TryParse, It may have been the best option.)
(虽然,在 TryParse 之前,它可能是最好的选择。)
回答by Chris Cudmore
Here's another chap who's also profiled the performance differences, and does so with a few different data types to see how much (if at all) they inherently affect the performance: int, bool, and DateTime.
这是另一个人,他也分析了性能差异,并使用了几种不同的数据类型来查看它们对性能的内在影响有多大(如果有的话):int、bool 和 DateTime。