Parsing Performance (If, Tryparse, Try-Catch)

Parsing Performance (If, TryParse, Try-Catch)

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.

"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

Therefore you assign, arbitrarily like in carbon credits, that the performance of try-catch is worse and 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.

(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):

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);
}

What is better: int.TryParse or try { int.Parse() } catch

Better is highly subjective. For instance, I personally prefer int.TryParse, since I most often don't care why the parsing fails, if it fails. However, int.Parse can (according to the documentation) throw three different exceptions:

  • the input is null
  • the input is not in a valid format
  • the input contains a number that produces an overflow

If you care about why it fails, then int.Parse is clearly the better choice.

As always, context is king.

How do I use TryParse or Try catch to explain to the user what he's doing wrong?

The compiler has detected that, if your try block throws an exception before TryParse runs, the number variable will never have a value assigned to it, so it won't allow you to use it later on.

Even when you're sure the code inside the try block couldn't possibly fail, the compiler is not.

int number;

try
{
Int32.TryParse(Console.ReadLine(), out number);
}
catch
{
Console.WriteLine("This only works with numbers!");
}

if (number < gameNumber) // if "try" fails, number is undefined

You're part way there. The call to TryParse already returns false if the conversion failed, so use that return value to decide when to display an error message to your user.

int number;

if (!Int32.TryParse(Console.ReadLine(), out number))
{
// parse failed ("number" is now 0), display message to user
Console.WriteLine("This only works with numbers!");

// start the next iteration of the loop, prompting the user again
// (otherwise, the number comparison runs, telling the user their guess is too small)
continue;
}

if (number < gameNumber)

Parse v. TryParse

Parse throws an exception if it cannot parse the value, whereas TryParse returns a bool indicating whether it succeeded.

TryParse does not just try/catch internally - the whole point of it is that it is implemented without exceptions so that it is fast. In fact the way it is most likely implemented is that internally the Parse method will call TryParse and then throw an exception if it returns false.

In a nutshell, use Parse if you are sure the value will be valid; otherwise use TryParse.

pros and cons of TryCatch versus TryParse

  • TryParse will be faster than catching an exception
  • TryParse indicates something expected - nothing exceptional is happening here, it's just that you suspect your data may not be valid.
  • TryParse isn't using exception handling for normal control flow

Basically, go with TryParse :)

By the way, your code can be rewritten as:

public static double GetDouble(object input, double defaultVal)
{
double parsed;
return double.TryParse(input.ToString(), out parsed)) ? parsed : defaultVal;
}

C#: When should I use TryParse?

It's pretty much as simple as this: Use Parse if you want an exception when you encounter invalid data; use TryParse if you don't. Your question seems, therefore, to be:

Why would you not want an exception if data is invalid?

Exceptions should only be used for exceptional cases, and the data being invalid might not be an exceptional case. Maybe you're writing a data cleansing program that's expecting to get invalid data and will try to infer what a reasonable value is when the data is invalid. Maybe the data isn't all that important and you can just skip the record that contains it.

It depends on context, and having the choice of Parse and TryParse methods lets you choose the appropriate parsing mechanism for yours.

Parsing with TryParse or Parse when data is theoretically always correct?

I look more at the scenario than the performance; if the expected behaviour is that it is valid, I generally use Parse (or ParseExact if available), and let the exception go. Unless I need to raise a specific error, in which case TryParse is handy.

If the data might be (say) an integer, then TryParse is preferable over Parse+catch.

With LINQ-to-XML: don't parse; instead, use the static conversion operators provided; so rather than:

...
select int.Parse(node.Value);

you should use

...
select(int) node;

this is even more important for things like DateTime, as it takes into account the standard XML formats. It also does the "expected" thing if the node doesn't exist (i.e. node is null):

select (int?)node;

will return a null value rather than throwing a NullReferenceException (which node.Value would do). There are static conversion operators for most expected data-types.

Which one is faster in processing and conversion int.Parse(), int.TryParse(), Convert.Int32()

Go read this ("Performance Profiling Parse vs. TryParse vs. ConvertTo") for much add'l info.

If you are unsure if the string is parsable, then int.TryParse() will be MUCH faster than either of the others and catching the exceptions.

Java Scope Issues: try-catch block, parsing String to Date

You need to define the variable outside the try scope, then use it from inside. This code will work to your expectation:

String stringDate = sc.next();
SimpleDateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy");
Date date = null;

try {
date = dateFormatter.parse(stringDate);
} catch(ParseException e) {
e.printStackTrace();
}

e = new Employee(id, login, salary, date, name);

You need to watch out now as while you create the new employee the date might be null. Therefore you might even go one step further and do that only if the date is not null. But in the snippet you have here the variable e is not defined anyway (or just used in the catch block).

String stringDate = sc.next();
SimpleDateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy");

try {
Date date = dateFormatter.parse(stringDate);
e = new Employee(id, login, salary, date, name);
} catch(ParseException e) {
e.printStackTrace();
}


Related Topics



Leave a reply



Submit