How to avoid throwing an exceptions for a built-in function?
Jonathan M Davis via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sat May 13 02:05:17 PDT 2017
On Friday, May 12, 2017 10:42:18 H. S. Teoh via Digitalmars-d-learn wrote:
> On Fri, May 12, 2017 at 12:47:04PM +0200, ag0aep6g via Digitalmars-d-learn
wrote:
> > On 05/12/2017 10:32 AM, k-five wrote:
> > > Interesting! I was worried about performance and for that I did not
> > > want to use try-catch.
> > > So (isNumberic) is a good solution.
> > > http://dlang.org/phobos/std_traits.html#isNumeric
> >
> > If you're doing this for speed, you better be benchmarking. Exceptions
> > are slow when they're thrown. But if no exception is being thrown,
> > try-catch is probably faster than checking isNumeric beforehand.
>
> Yes, when it comes to performance-related issues, always profile,
> profile, profile. (Or benchmark, benchmark, benchmark. Anything that
> gives you actual measurements rather than subjective judgment calls.)
> Far too often, what we think will perform poorly is actually nowhere
> near the real bottleneck in the program, and we end up wasting too much
> time "optimizing" something that doesn't even make a noticeable
> difference in the end. Whereas, using a profiler early on will help you
> zero in on the real bottlenecks, and you could potentially make huge
> performance savings with much less effort.
For the most part, when parsing a string, std.conv.to's approach of just
parsing the string and throwing an exception if/when it fails is the most
efficient, because it's only going to parse the string once, whereas calling
a function to validate the string's format and _then_ do the conversion
would mean parsing the string twice. It's just that if you are in a
situation where the string is likely not to be in the correct format, then
having a bunch of exceptions thrown will harm performance. To best handle
that, we'd need an alternate conversion function that did something like
return the failure condition and passed the result via an out parameter or
one which took a default value and returned that on failure instead of what
was actaully parsed. So, ideally, we'd have other functions in std.conv to
handle such cases, but in the vast majority of cases, throwing an exception
on failure is going to be the most efficient solution.
But obviously, to know what's actually happening with your code, you're
going to have to profile and benchmark it - especially if you're throwing
exceptions on a regular basis but not super frequently, because then it's
quickly an open question as to whether parsing twice to avoid the exception
or letting the exception be thrown and caught would be faster.
Odds are though that unless you're converting in a tight loop, the relative
costs won't matter much, even if one is clearly more expensive than the
other, simply because it's not a bottleneck in your program. But you won't
know that for sure unless you profile.
However, unless you're parsing a lot of invalid strings, I'd be very
surprised if always parsing twice were more efficient than parsing only once
and throwing an exception on failure. And D exceptions are fairly efficient
at this point if you don't call toString, because we stripped out most of
the string processing that they were doing up front before. It used to be
pretty painful when you did a lot of tests that tested the error cases,
because the exceptions really increased the time that the tests took, but
that's no longer the case (IIRC, the improvements literally saved seconds of
execution time in std.datetime's unit tests).
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list