1
\$\begingroup\$

I am curious as to what the performance/functional differences are between:

private bool OftenCalledMethod(string s)
{
    Regex reg = new Regex(@"^matchme$", RegexOptions.IgnoreCase);
    return (reg.IsMatch(s));
}

Versus:

readonly Regex reg = new Regex(@"^matchme$", RegexOptions.IgnoreCase);
private bool OftenCalledMethod(string s)
{
    return (reg.IsMatch(s));
}

Does the compiler optimize the former in such a way that it doesn't matter? Or is the object reg being allocated repeatedly and unnecessarily?

\$\endgroup\$
2
\$\begingroup\$

I would go with the former unless you profile your code and it tells you that the constructor for Regex is using a significant amount of time.

Creating the Regex inside your method makes the clear statement that this given Regex is being used by only this method. The compiler doesn't care, but someone maintaining your code in the future might care.

Running a profiler is necessary for really optimizing your code. There are some things that are always likely to be bad (O(n^3) algorithms for instance), but I've learned by experience that I can't tell just by looking where the time is being wasted in my code. Profile it and see what you learn.

If your profiling results tell you that the constructor of Regex is using too much time, then definitely move it outside the method. If you do that though, you should add comments explaining why. (Keep thinking about the poor person maintaining your code in the future, it just might be you.)

\$\endgroup\$
1
\$\begingroup\$

Just the creation of the Regex class is unlikely to take too much time. You are just initializing two properties.

Do not mistake the initialization with the much more costly execution.

In any case, do not over optimize without backing up your assumptions with performance data gathered by a profiling tool.

The added benefit of profiling your code, is that now you will know much better what actually happens during execution.

\$\endgroup\$
1
\$\begingroup\$

Definitely profile your code before doing any optimization. It's certainly reasonable to make some up-front decisions based on what you think might be optimal code, but once you get reasonable and working code, don't start hacking away at it in the hopes of gaining some sort of optimization. Time it, profile it, etc to find the slow spots, then focus on those.

As for the cost of initialization vs. use with regex objects, I'm not personally familiar with C#'s handling of them, but in Python, there is a cost to creating a regex which goes beyond just initializing a few member variables.

import re
from timeit import Timer

test_str = 'abra, abra, cadabra'
test_re = 'c.d'

def inside(s):
    r = re.compile(test_re)
    return r.match(s)

r = re.compile(test_re)
def outside(s):
    return r.match(s)

print "inside =", Timer("inside(test_str)", "from __main__ import inside, test_str").timeit()
print "outside =", Timer("outside(test_str)", "from __main__ import outside, test_str").timeit()

The output from the little test code above clearly shows that creating the regex inside the function each time it is called is a significant performance loss.

inside = 3.24013303367
outside = 1.45581882614
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.