I have a method as below which searches a collection and evaluates a condition recursively:
public static bool Recurse(this INodeViewModel node, Func<INodeViewModel,bool> predicate)
{
INodeViewModel currentNode = node;
return predicate(currentNode) || node.Children.Select(x => Recurse(x, predicate)).Any(found => found);
}
Alternatively this can be implemented using a stack to avoid recursion as below:
public static bool UsingStack(this INodeViewModel node, Func<INodeViewModel, bool> predicate)
{
var stack = new Stack<INodeViewModel>();
stack.Push(node);
while(stack.Any())
{
var current = stack.Pop();
if (predicate(current))
return true;
foreach (var child in current.Children)
{
stack.Push(child);
}
}
return false;
}
My question is, does the stack version offer any performance benefits when the depth of the tree is large compared to the recursive version?
My question is, does the stack version offer any performance benefits when the depth of the tree is large compared to the recursive version?
Yes. The recursive version is infinitely slower than the iterative version when the depth of the tree is large. That's because the recursive version will blow the call stack, cause an unstoppable out-of-stack-space exception, and terminate your program before the bool is returned. The iterative version will not do that until heap space is exhausted, and heap space is potentially thousands of times larger than stack space.
Not giving a result at all is obviously worse performance than giving a result in any finite amount of time.
If however your question really is "does the stack version offer any benefit when the tree is deep, but not so deep that it blows the stack" then the answer is:
You've already written the program both ways. Run it and find out. Don't show random strangers on the internet pictures of two horses and ask which is faster; race them and then you'll know.
Also: I would be inclined to solve your problem by writing methods that do traversals and yield each element. If you can write methods IEnumerable<INode> BreadthFirstTraversal(this INode node) and IEnumerable<INode> DepthFirstTraversal(this INode node) then you don't need to be writing your own search; you can just say node.DepthFirstTraversal().Where(predicate).FirstOrDefault() when you want to search.
Let's make this clear first: Recursion is not for speed. Anything it does can be done at least as fast, and often faster, with iteration. Recursion's benefits come in the clarity of the code.
With that said, unless you absolutely need the fastest possible code (and frankly, you almost never do), the second (data-recursive) version isn't even worth considering, as it adds complexity for no good reason. It's especially worthless in C#, as each Stack operation involves a method call, and eliminating recursion is mostly about getting rid of the method calls. You're almost certainly adding work, forcing method calls for stuff that the runtime could handle far more efficiently with the built-in stack.
Eric makes a reasonable point about stack overflows, but in order for that to be an issue, you'd need a tree thousands of nodes deep, or you'd have to be searching from an already deep call stack, or the predicate would need to be recursive itself (possibly by triggering other searches). With an even slightly balanced tree and a predicate that doesn't cause more recursion, stack depth should not be an issue; the default stack is already large enough to handle quite a bit of recursion, and can be made bigger if needed.
With all that said, though: I'm guessing, as are you, as is everyone who hasn't actually implemented and tested both versions. If you care that much, time it.
The second version has several advantages:
You can easily switch from DFS to BFS by using a Queue instead of a Stack.
If depth is too large, it will throw an OutOfMemoryException which can be handled. (I believe a StackOverflowException is automatically rethrown).
Performance and memory usage might be better, because the recursive approach save all local variables (including compiler generated) on the call stack.
Related
ECMA-335, III.2.4 specifies tail. prefix that can be used in recursive functions. However, I could not find its usage neither in C# nor in F# code. Are there any example of using in?
You are not going to find it in any code produced by the current MS C# compiler. You will find it in code produced from the F# compiler, but not as much as you might expect, for almost opposite reasons.
Now, to first correct one mistake in your statement:
ECMA-335, III.2.4 specifies tail. prefix that can be used in recursive functions.
This is not strictly true. The tail. prefix can be used in tail-called calls; not all recursive functions are tail-recursion, and not all tail-calls are part of recursion.
A tail call is any call to a function (including an OOP method) where the last operation in that code-path is to make that call and then return the value it returns, or just return if the function called doesn't return a value. Hence in:
int DoSomeCalls(int x)
{
if(A(x))
return B(x);
if(DoSomeCalls(x * 2) > 3)
{
int ret = C(x);
return ret;
}
return D(DoSomeCalls(x-1));
}
Here, the calls to B, and D are tail calls, because the only thing done after the call is to return the value they'd returned. The call to C isn't a tail call, but it can be easily converted to one by removing the redundant assignment to ret by just returning directly. The call to A is not a tail call, and the nor are the call to DoSomeCalls, though they are recursive.
Now, the normal function call mechanism is implementation-dependent, but generally involves saving enrigstered values that might be needed after the call onto the stack, putting parameters onto the stack and/or into registers along with the current instruction position (to return to), moving the instruction pointer, and then reading the return value from a register or the stack when the instruction pointer is moved back to after where the call was done. With a tail call it's possible to skip a lot of this, because the called-into function can use the current stack frame and then return straight to the earlier caller.
The tail. prefix requests that this be done with a call.
While this isn't necessarily related to recursion, you were correct in talking about recursion, because the benefits of eliminating tail calls is greater in recursive cases than otherwise; making calls that are O(n) in stack space when actually using the function-call mechanism become O(1) in stack-space, along with reducing the per-item constant time costs lower (so it's still O(n) in this regard, but O(n) time means it takes n×k seconds, and we have a smaller k). In many cases this can be the difference between a call that works, and a call that throws a StackOverflowException.
Now, in ECMA-335 there are a few cases stated about how tail. may not always be honoured. In particular there is the text in §III.2.4 that states:
There can also be implementation-specific restrictions that prevent the tail. prefix from being obeyed in certain cases.
At its loosest, we could interpret this as preventing it in all manner of cases.
Conversely, the jitter is allowed to apply all manner of optimisations, including performing tail call elimination even when it wasn't requested by tail.
Because of this, there are in fact four ways to do tail-call elimination in IL:
Use the tail. prefix just before the call, and have it honoured (not guaranteed).
Don't use the tail. prefix before the call, but have the jitter decide to apply it any way (even less guaranteed).
Use the jmp IL instruction which is effectively a special case of tail call elimination (never used by C# because it produces unverifiable code for a normally relatively small gain, though it can be the easiest approach sometimes when hand-coding due to its relative simplicity).
Re-write the whole method to use a different approach; in particular the sort of recursive code that most benefits from tail call elimination can be re-written to explicitly use the sort of iterative algorithm the tail-call elimination effectively turns the recursion into.* (In other words, the tail-call elimination happens before the jitting or even the compilation).
(There's also sort of the case where the call is inlined, since it doesn't require a new stack frame, and indeed has normally a stronger improvement overall, and then in turn often allows even further optimisations to be performed, but it isn't generally considered a case of tail-call elimination because it's a call elimination that doesn't depend on it being a tail call).
Now, the first implementations of the jitter tended not to do tail call elimination in a lot of cases, even if it was requested.
Meanwhile at the C# side of things, there was a decision not to emit tail. There is a general approach with C# of not heavily optimising the code produced. There are some optimisations done (in particular, dead code removal), but for the most part since the optimisation efforts could just duplicate those done by the jitter (or even get in their way) the downsides of optimisation (more complications means more possible bugs, and the IL would be more confusing to many developers) relatively outweigh the upsides. Use of tail. is a classic example of this, because sometimes insisting on tail calls actually costs more than it saves with .NET so if the jitter is already trying to work out when it's a good idea, then there's a bigger chance that the C# compiler would be just making things worse a lot of the time, and making no difference the rest.
It's also worth noting that with the styles of coding most common with a C-style language like C#:
Developers tend not to write code that would particularly benefit from tail-call elimination compared to the styles more common in other languages.
Developers tend to know how to optimise the sort of recursive calls that would most benefit from tail-call elimination by re-writing them to be iterative.
Developers tend to have written them in the iterative manner in the first place.
Now, along came F#.
With the sort of functional and declarative programming F# encourages, there are a lot of cases where what is most naturally done in an iterative way in C# is most naturally done with a recursive approach. Where people hacking in C-style languages learn to turn recursive cases into iterative code, people hacking in F#-style languages learn to turn iterative cases into recursive code, and non-tail-calling recursive code into tail-calling recursive code.
So F# used tail. a lot.
And it got StackOverflowException a lot, because the jitter wasn't honouring it.
This is one of the things that led the jitter people to increase the number of cases where they eliminated tail calls, both in general and even further if tail. is used.
Meanwhile, the F# people couldn't just depend on tail. so F#'s compiler will optimise much more heavily than C#'s; just as we can manually rewrite recursive calls to be iterative as in the footnote, so the F# compiler does the equivalent when producing IL.
And for this reason, a lot of the time when you write an F# method where you'd expect to see some IL that uses tail., what you'd actually get is IL that does the equivalent thing iteratively.
However, F# will still use tail. when a method calls another method in a mutually-recursive manner like:
let rec even n =
if n = 0 then
true
else
odd (n-1)
and odd n =
if n = 1 then
true
else
even (n-1)
Which I totally stole from this answer because I've only played a tiny bit with F# so I'd rather depend upon someone more familiar than I am.
In this case, because the tail-calls aren't in a single function, it can't just be rewritten to eliminate it at the IL compilation point, so it has to hope the jitter will do the elimination, and uses tail. to increase the chances it will.
*An example of turning a recursive call into an iterative would be to start with a recursive call like:
void ClearAllNodes(Node node)
{
if(node != null)
{
node.Value = null;
ClearAllNodes(node.Next)
}
}
The simplest change is to then manually add what a tail-call elimination does, by ourselves setting up the parameter, and jumping back to the start of the method:
void ClearAllNodes(Node node)
{
start:
if(node != null)
{
node.Value = null;
node = node.Next;
goto start;
}
}
Since there are good reasons to avoid goto if we can, we would generally change it to something that does the same through more strictly-defined looping mechanisms:
void ClearAllNodes(Node node)
{
while(node != null)
{
node.Value = null;
node = node.Next;
}
}
When I ran ReSharper on my code, for example:
if (some condition)
{
Some code...
}
ReSharper gave me the above warning (Invert "if" statement to reduce nesting), and suggested the following correction:
if (!some condition) return;
Some code...
I would like to understand why that's better. I always thought that using "return" in the middle of a method problematic, somewhat like "goto".
It is not only aesthetic, but it also reduces the maximum nesting level inside the method. This is generally regarded as a plus because it makes methods easier to understand (and indeed, many static analysis tools provide a measure of this as one of the indicators of code quality).
On the other hand, it also makes your method have multiple exit points, something that another group of people believes is a no-no.
Personally, I agree with ReSharper and the first group (in a language that has exceptions I find it silly to discuss "multiple exit points"; almost anything can throw, so there are numerous potential exit points in all methods).
Regarding performance: both versions should be equivalent (if not at the IL level, then certainly after the jitter is through with the code) in every language. Theoretically this depends on the compiler, but practically any widely used compiler of today is capable of handling much more advanced cases of code optimization than this.
A return in the middle of the method is not necessarily bad. It might be better to return immediately if it makes the intent of the code clearer. For example:
double getPayAmount() {
double result;
if (_isDead) result = deadAmount();
else {
if (_isSeparated) result = separatedAmount();
else {
if (_isRetired) result = retiredAmount();
else result = normalPayAmount();
};
}
return result;
};
In this case, if _isDead is true, we can immediately get out of the method. It might be better to structure it this way instead:
double getPayAmount() {
if (_isDead) return deadAmount();
if (_isSeparated) return separatedAmount();
if (_isRetired) return retiredAmount();
return normalPayAmount();
};
I've picked this code from the refactoring catalog. This specific refactoring is called: Replace Nested Conditional with Guard Clauses.
This is a bit of a religious argument, but I agree with ReSharper that you should prefer less nesting. I believe that this outweighs the negatives of having multiple return paths from a function.
The key reason for having less nesting is to improve code readability and maintainability. Remember that many other developers will need to read your code in the future, and code with less indentation is generally much easier to read.
Preconditions are a great example of where it is okay to return early at the start of the function. Why should the readability of the rest of the function be affected by the presence of a precondition check?
As for the negatives about returning multiple times from a method - debuggers are pretty powerful now, and it's very easy to find out exactly where and when a particular function is returning.
Having multiple returns in a function is not going to affect the maintainance programmer's job.
Poor code readability will.
As others have mentioned, there shouldn't be a performance hit, but there are other considerations. Aside from those valid concerns, this also can open you up to gotchas in some circumstances. Suppose you were dealing with a double instead:
public void myfunction(double exampleParam){
if(exampleParam > 0){
//Body will *not* be executed if Double.IsNan(exampleParam)
}
}
Contrast that with the seemingly equivalent inversion:
public void myfunction(double exampleParam){
if(exampleParam <= 0)
return;
//Body *will* be executed if Double.IsNan(exampleParam)
}
So in certain circumstances what appears to be a a correctly inverted if might not be.
The idea of only returning at the end of a function came back from the days before languages had support for exceptions. It enabled programs to rely on being able to put clean-up code at the end of a method, and then being sure it would be called and some other programmer wouldn't hide a return in the method that caused the cleanup code to be skipped. Skipped cleanup code could result in a memory or resource leak.
However, in a language that supports exceptions, it provides no such guarantees. In a language that supports exceptions, the execution of any statement or expression can cause a control flow that causes the method to end. This means clean-up must be done through using the finally or using keywords.
Anyway, I'm saying I think a lot of people quote the 'only return at the end of a method' guideline without understanding why it was ever a good thing to do, and that reducing nesting to improve readability is probably a better aim.
I'd like to add that there is name for those inverted if's - Guard Clause. I use it whenever I can.
I hate reading code where there is if at the beginning, two screens of code and no else. Just invert if and return. That way nobody will waste time scrolling.
http://c2.com/cgi/wiki?GuardClause
It doesn't only affect aesthetics, but it also prevents code nesting.
It can actually function as a precondition to ensure that your data is valid as well.
This is of course subjective, but I think it strongly improves on two points:
It is now immediately obvious that your function has nothing left to do if condition holds.
It keeps the nesting level down. Nesting hurts readability more than you'd think.
Multiple return points were a problem in C (and to a lesser extent C++) because they forced you to duplicate clean-up code before each of the return points. With garbage collection, the try | finally construct and using blocks, there's really no reason why you should be afraid of them.
Ultimately it comes down to what you and your colleagues find easier to read.
Guard clauses or pre-conditions (as you can probably see) check to see if a certain condition is met and then breaks the flow of the program. They're great for places where you're really only interested in one outcome of an if statement. So rather than say:
if (something) {
// a lot of indented code
}
You reverse the condition and break if that reversed condition is fulfilled
if (!something) return false; // or another value to show your other code the function did not execute
// all the code from before, save a lot of tabs
return is nowhere near as dirty as goto. It allows you to pass a value to show the rest of your code that the function couldn't run.
You'll see the best examples of where this can be applied in nested conditions:
if (something) {
do-something();
if (something-else) {
do-another-thing();
} else {
do-something-else();
}
}
vs:
if (!something) return;
do-something();
if (!something-else) return do-something-else();
do-another-thing();
You'll find few people arguing the first is cleaner but of course, it's completely subjective. Some programmers like to know what conditions something is operating under by indentation, while I'd much rather keep method flow linear.
I won't suggest for one moment that precons will change your life or get you laid but you might find your code just that little bit easier to read.
Performance-wise, there will be no noticeable difference between the two approaches.
But coding is about more than performance. Clarity and maintainability are also very important. And, in cases like this where it doesn't affect performance, it is the only thing that matters.
There are competing schools of thought as to which approach is preferable.
One view is the one others have mentioned: the second approach reduces the nesting level, which improves code clarity. This is natural in an imperative style: when you have nothing left to do, you might as well return early.
Another view, from the perspective of a more functional style, is that a method should have only one exit point. Everything in a functional language is an expression. So if statements must always have an else clauses. Otherwise the if expression wouldn't always have a value. So in the functional style, the first approach is more natural.
There are several good points made here, but multiple return points can be unreadable as well, if the method is very lengthy. That being said, if you're going to use multiple return points just make sure that your method is short, otherwise the readability bonus of multiple return points may be lost.
Performance is in two parts. You have performance when the software is in production, but you also want to have performance while developing and debugging. The last thing a developer wants is to "wait" for something trivial. In the end, compiling this with optimization enabled will result in similar code. So it's good to know these little tricks that pay off in both scenarios.
The case in the question is clear, ReSharper is correct. Rather than nesting if statements, and creating new scope in code, you're setting a clear rule at the start of your method. It increases readability, it will be easier to maintain, and it reduces the amount of rules one has to sift through to find where they want to go.
Personally I prefer only 1 exit point. It's easy to accomplish if you keep your methods short and to the point, and it provides a predictable pattern for the next person who works on your code.
eg.
bool PerformDefaultOperation()
{
bool succeeded = false;
DataStructure defaultParameters;
if ((defaultParameters = this.GetApplicationDefaults()) != null)
{
succeeded = this.DoSomething(defaultParameters);
}
return succeeded;
}
This is also very useful if you just want to check the values of certain local variables within a function before it exits. All you need to do is place a breakpoint on the final return and you are guaranteed to hit it (unless an exception is thrown).
Avoiding multiple exit points can lead to performance gains. I am not sure about C# but in C++ the Named Return Value Optimization (Copy Elision, ISO C++ '03 12.8/15) depends on having a single exit point. This optimization avoids copy constructing your return value (in your specific example it doesn't matter). This could lead to considerable gains in performance in tight loops, as you are saving a constructor and a destructor each time the function is invoked.
But for 99% of the cases saving the additional constructor and destructor calls is not worth the loss of readability nested if blocks introduce (as others have pointed out).
Many good reasons about how the code looks like. But what about results?
Let's take a look to some C# code and its IL compiled form:
using System;
public class Test {
public static void Main(string[] args) {
if (args.Length == 0) return;
if ((args.Length+2)/3 == 5) return;
Console.WriteLine("hey!!!");
}
}
This simple snippet can be compiled. You can open the generated .exe file with ildasm and check what is the result. I won't post all the assembler thing but I'll describe the results.
The generated IL code does the following:
If the first condition is false, jumps to the code where the second is.
If it's true jumps to the last instruction. (Note: the last instruction is a return).
In the second condition the same happens after the result is calculated. Compare and: got to the Console.WriteLine if false or to the end if this is true.
Print the message and return.
So it seems that the code will jump to the end. What if we do a normal if with nested code?
using System;
public class Test {
public static void Main(string[] args) {
if (args.Length != 0 && (args.Length+2)/3 != 5)
{
Console.WriteLine("hey!!!");
}
}
}
The results are quite similar in IL instructions. The difference is that before there were two jumps per condition: if false go to next piece of code, if true go to the end. And now the IL code flows better and has 3 jumps (the compiler optimized this a bit):
First jump: when Length is 0 to a part where the code jumps again (Third jump) to the end.
Second: in the middle of the second condition to avoid one instruction.
Third: if the second condition is false, jump to the end.
Anyway, the program counter will always jump.
In theory, inverting if could lead to better performance if it increases branch prediction hit rate. In practice, I think it is very hard to know exactly how branch prediction will behave, especially after compiling, so I would not do it in my day-to-day development, except if I am writing assembly code.
More on branch prediction here.
That is simply controversial. There is no "agreement among programmers" on the question of early return. It's always subjective, as far as I know.
It's possible to make a performance argument, since it's better to have conditions that are written so they are most often true; it can also be argued that it is clearer. It does, on the other hand, create nested tests.
I don't think you will get a conclusive answer to this question.
There are a lot of insightful answers there already, but still, I would to direct to a slightly different situation: Instead of precondition, that should be put on top of a function indeed, think of a step-by-step initialization, where you have to check for each step to succeed and then continue with the next. In this case, you cannot check everything at the top.
I found my code really unreadable when writing an ASIO host application with Steinberg's ASIOSDK, as I followed the nesting paradigm. It went like eight levels deep, and I cannot see a design flaw there, as mentioned by Andrew Bullock above. Of course, I could have packed some inner code to another function, and then nested the remaining levels there to make it more readable, but this seems rather random to me.
By replacing nesting with guard clauses, I even discovered a misconception of mine regarding a portion of cleanup-code that should have occurred much earlier within the function instead of at the end. With nested branches, I would never have seen that, you could even say they led to my misconception.
So this might be another situation where inverted ifs can contribute to a clearer code.
It's a matter of opinion.
My normal approach would be to avoid single line ifs, and returns in the middle of a method.
You wouldn't want lines like it suggests everywhere in your method but there is something to be said for checking a bunch of assumptions at the top of your method, and only doing your actual work if they all pass.
In my opinion early return is fine if you are just returning void (or some useless return code you're never gonna check) and it might improve readability because you avoid nesting and at the same time you make explicit that your function is done.
If you are actually returning a returnValue - nesting is usually a better way to go cause you return your returnValue just in one place (at the end - duh), and it might make your code more maintainable in a whole lot of cases.
I'm not sure, but I think, that R# tries to avoid far jumps. When You have IF-ELSE, compiler does something like this:
Condition false -> far jump to false_condition_label
true_condition_label:
instruction1
...
instruction_n
false_condition_label:
instruction1
...
instruction_n
end block
If condition is true there is no jump and no rollout L1 cache, but jump to false_condition_label can be very far and processor must rollout his own cache. Synchronising cache is expensive. R# tries replace far jumps into short jumps and in this case there is bigger probability, that all instructions are already in cache.
I think it depends on what you prefer, as mentioned, theres no general agreement afaik.
To reduce annoyment, you may reduce this kind of warning to "Hint"
My idea is that the return "in the middle of a function" shouldn't be so "subjective".
The reason is quite simple, take this code:
function do_something( data ){
if (!is_valid_data( data ))
return false;
do_something_that_take_an_hour( data );
istance = new object_with_very_painful_constructor( data );
if ( istance is not valid ) {
error_message( );
return ;
}
connect_to_database ( );
get_some_other_data( );
return;
}
Maybe the first "return" it's not SO intuitive, but that's really saving.
There are too many "ideas" about clean codes, that simply need more practise to lose their "subjective" bad ideas.
There are several advantages to this sort of coding but for me the big win is, if you can return quick you can improve the speed of your application. IE I know that because of Precondition X that I can return quickly with an error. This gets rid of the error cases first and reduces the complexity of your code. In a lot of cases because the cpu pipeline can be now be cleaner it can stop pipeline crashes or switches. Secondly if you are in a loop, breaking or returning out quickly can save you a lots of cpu. Some programmers use loop invariants to do this sort of quick exit but in this you can broke your cpu pipeline and even create memory seek problem and mean the the cpu needs to load from outside cache. But basically I think you should do what you intended, that is end the loop or function not create a complex code path just to implement some abstract notion of correct code. If the only tool you have is a hammer then everything looks like a nail.
I'm stuck at finding a solution. C#, .NET 4.0, VS2010
I can easily write a recursive one, but can't for the life of me figure out something that won't overflow the stack if the tree is arbitrarily large.
This is a binary tree question, and i am trying to write a
public IEnumerable<T> Values()
method.
Here is the full code in case you are interested: http://pastebin.com/xr2f3y7g
Obviously, the version currently in there doesn't work. I probably should mention that I am a newbie in C#, transitioning from C++.
Here is a method for inorder traversal, that uses explicit stack. The stack is created on the heap, so it can be much larger, than the stack the processor uses.
public IEnumerable<T> Values()
{
Stack<Node> stack = new Stack<Node>();
Node current = this.root;
while(current != null)
{
while(current.leftChild != null)
{
stack.Push(current);
current = current.leftChild;
}
yield return current.data;
while(current.rightChild == null && stack.Count > 0)
{
current = stack.Pop();
yield return current.data;
}
current = current.rightChild;
}
}
If you can't use a stack and your nodes happen to have parent pointers, you can try solutions from this question
Assuming the tree is anywhere near balanced, its maximum depth is log2(n), so you'd need a huge tree to overflow the stack.
You can transform any recursive algorithm into an iterative one, but in this case, it will likely require either backward pointers or an explicit stack, both of which look expensive.
Having said that, recursion is typically not so great in .NET because any local variables in calling instances of a method cannot be GC'ed until the stack gets unwound after the terminating condition. I don't know whether the JIT will automatically optimize tail-end recursion to make it iterative, but that would help.
I've been trying to find an answer to this question for a few hours now on the web and on this site, and I'm not quite there.
I understand that .NET allocates 1MB to apps, and that it's best to avoid stack overflow by recoding instead of forcing stack size.
I'm working on a "shortest path" app that works great up to about 3000 nodes, at which point it overflows. Here's the method that causes problems:
public void findShortestPath(int current, int end, int currentCost)
{
if (!weight.ContainsKey(current))
{
weight.Add(current, currentCost);
}
Node currentNode = graph[current];
var sortedEdges = (from entry in currentNode.edges orderby entry.Value ascending select entry);
foreach (KeyValuePair<int, int> nextNode in sortedEdges)
{
if (!visited.ContainsKey(nextNode.Key) || !visited[nextNode.Key])
{
int nextNodeCost = currentCost + nextNode.Value;
if (!weight.ContainsKey(nextNode.Key))
{
weight.Add(nextNode.Key, nextNodeCost);
}
else if (weight[nextNode.Key] > nextNodeCost)
{
weight[nextNode.Key] = nextNodeCost;
}
}
}
visited.Add(current, true);
foreach (KeyValuePair<int, int> nextNode in sortedEdges)
{
if(!visited.ContainsKey(nextNode.Key) || !visited[nextNode.Key]){
findShortestPath(nextNode.Key, end, weight[nextNode.Key]);
}
}
}//findShortestPath
For reference, the Node class has one member:
public Dictionary<int, int> edges = new Dictionary<int, int>();
graph[] is:
private Dictionary<int, Node> graph = new Dictonary<int, Node>();
I've tried to opimize the code so that it isn't carrying any more baggage than needed from one iteration (recursion?) to the next, but with a 100K-Node graph with each node having between 1-9 edges it's going to hit that 1MB limit pretty quickly.
Anyway, I'm new to C# and code optimization, if anyone could give me some pointers (not like this) I would appreciate it.
The classic technique to avoid deep recursive stack dives is to simply avoid recursion by writing the algorithm iteratively and managing your own "stack" with an appropriate list data structure. Most likely you will need this approach here given the sheer size of your input set.
A while back I explored this problem in my blog. Or, rather, I explored a related problem: how do you find the depth of a binary tree without using recursion? A recursive tree depth solution is trivial, but blows the stack if the tree is highly imbalanced.
My recommendation is to study ways of solving this simpler problem, and then decide which of them, if any, could be adapted to your slightly more complex algorithm.
Note that in these articles the examples are given entirely in JScript. However, it should not be difficult to adapt them to C#.
Here we start by defining the problem.
http://blogs.msdn.com/ericlippert/archive/2005/07/27/recursion-part-one-recursive-data-structures-and-functions.aspx
The first attempt at a solution is the classic technique that you'll probably adopt: define an explicit stack; use it rather than relying upon the operating system and compiler implementing the stack for you. This is what most people do when faced with this problem.
http://blogs.msdn.com/ericlippert/archive/2005/08/01/recursion-part-two-unrolling-a-recursive-function-with-an-explicit-stack.aspx
The problem with that solution is that it's a bit of a mess. We can go even farther than simply making our own stack. We can make our own little domain-specific virtual machine that has its own heap-allocated stack, and then solve the problem by writing a program that targets that machine! This is actually easier than it sounds; the operations of the machine can be extremely high level.
http://blogs.msdn.com/ericlippert/archive/2005/08/04/recursion-part-three-building-a-dispatch-engine.aspx
And finally, if you are really a glutton for punishment (or a compiler developer) you can rewrite your program in Continuation Passing Style, thereby eliminating the need for a stack at all:
http://blogs.msdn.com/ericlippert/archive/2005/08/08/recursion-part-four-continuation-passing-style.aspx
http://blogs.msdn.com/ericlippert/archive/2005/08/11/recursion-part-five-more-on-cps.aspx
http://blogs.msdn.com/ericlippert/archive/2005/08/15/recursion-part-six-making-cps-work.aspx
CPS is a particularly clever way of moving the implicit stack data structure off the system stack and onto the heap by encoding it in the relationships between a bunch of delegates.
Here are all of my articles on recursion:
http://blogs.msdn.com/ericlippert/archive/tags/Recursion/default.aspx
You could convert the code to use a 'work queue' rather than being recursive. Something along the following pseudocode:
Queue<Task> work;
while( work.Count != 0 )
{
Task t = work.Dequeue();
... whatever
foreach(Task more in t.MoreTasks)
work.Enqueue(more);
}
I know that is cryptic but it's the basic concept of what you'll need to do. Since your only getting 3000 nodes with your current code, you will at best get to 12~15k without any parameters. So you need to kill the recursion completely.
Is your Node a struct or a class? If it's the former, make it a class so that it's allocated on the heap instead of on the stack.
I would first verify that you are actually overflowing the stack: you actually see a StackOverflowException get thrown by the runtime.
If this is indeed the case, you have a few options:
Modify your recursive function so that the .NET runtime can convert it into a tail-recursive function.
Modify your recursive function so that it is iterative and uses a custom data structure rather than the managed stack.
Option 1 is not always possible, and assumes that the rules the CLR uses to generate tail recursive calls will remain stable in the future. The primary benefit, is that when possible, tail recursion is actually a convenient way of writing recursive algorithms without sacrificing clarity.
Option 2 is a more work, but is not sensitive to the implementation of the CLR and can be implemented for any recursive algorithm (where tail recursion may not always be possible). Generally, you need to capture and pass state information between iterations of some loop, together with information on how to "unroll" the data structure that takes the places of the stack (typically a List<> or Stack<>). One way of unrolling recursion into iteration is through continuation passing pattern.
More resources on C# tail recursion:
Why doesn't .NET/C# optimize for tail-call recursion?
http://geekswithblogs.net/jwhitehorn/archive/2007/06/06/113060.aspx
I would first make sure I know why I'm getting a stack overflow. Is it actually because of the recursion? The recursive method isn't putting much onto the stack. Maybe it's because of the storage of the nodes?
Also, BTW, I don't see the end parameter ever changing. That suggests it doesn't need to be a parameter, carried on each stack frame.
Are there any general rules when using recursion on how to avoid stackoverflows?
How many times you will be able to recurse will depend on:
The stack size (which is usually 1MB IIRC, but the binary can be hand-edited; I wouldn't recommend doing so)
How much stack each level of the recursion uses (a method with 10 uncaptured Guid local variables will be take more stack than a method which doesn't have any local variables, for example)
The JIT you're using - sometimes the JIT will use tail recursion, other times it won't. The rules are complicated and I can't remember them. (There's a blog post by David Broman back from 2007, and an MSDN page from the same author/date, but they may be out of date by now.)
How to avoid stack overflows? Don't recurse too far :) If you can't be reasonably sure that your recursion will terminate without going very far (I'd be worried at "more than 10" although that's very safe) then rewrite it to avoid recursion.
It really depends on what recursive algorithm you're using. If it's simple recursion, you can do something like this:
public int CalculateSomethingRecursively(int someNumber)
{
return doSomethingRecursively(someNumber, 0);
}
private int doSomethingRecursively(int someNumber, int level)
{
if (level >= MAX_LEVEL || !shouldKeepCalculating(someNumber))
return someNumber;
return doSomethingRecursively(someNumber, level + 1);
}
It's worth noting that this approach is really only useful where the level of recursion can be defined as a logical limit. In the case that this cannot occur (such as a divide and conquer algorithm), you will have to decide how you want to balance simplicity versus performance versus resource limitations. In these cases, you may have to switch between methods once you hit an arbritrary pre-defined limit. An effective means of doing this that I have used in the quicksort algorithm is to do it as a ratio of the total size of the list. In this case, the logical limit is a result of when conditions are no longer optimal.
I am not aware of any hard set to avoid stackoverflows. I personally try to ensure -
1. I have my base cases right.
2. The code reaches the base case at some point.
If you're finding yourself generating that many stack frames, you might want to consider unrolling your recursion into a loop.
Especially if you are doing multiple levels of recursion (A->B->C->A->B...) you might find that you can extract one of those levels into a loop and save yourself some memory.
The normal limit, if not much is left on the stack between successive calls, is around 15000-25000 levels deep. 25% of that if you are on IIS 6+.
Most recursive algorhitms can be expressed iteratively.
There are various way to increase allocated stack space, but I'll rather let you find an iterative version first. :)
Other than having a reasonable stack size and making sure you divide and conquer your problem such that you continually work on a smaller problem, not really.
I just thought of tail-recursion, but it turned out, that C# does not support it. However the .Net-Framework seems to support it:
http://blogs.msdn.com/abhinaba/archive/2007/07/27/tail-recursion-on-net.aspx
The default stack size for a thread is 1 MB, if you're running under the default CLR. However, other hosts may change that. For example the ASP host changes the default to 256 KB. This means that you may have code that runs perfectly well under VS, but breaks when you deploy it to the real hosting environment.
Fortunately you can specify a stack size, when you create a new thread by using the correct constructor. In my experience it is rarely necessary, but I have seen one case where this was the solution.
You can edit the PE header of the binary itself to change the default size. This is useful if you want to change the size for the main thread. Otherwise I would recommend using the appropriate constructor when creating threads.
I wrote a short article about this here. Basically, I pass an optional parameter called, depth, adding 1 to it each time I go deeper into it. Within the recursive method I check the depth for a value. If it is greater than the value I set, I throw an exception. The value (threshold) would be dependent on your applications needs.
Remember, if you have to ask about system limits, then you are probably doing something horribly wrong.
So, if you think you might get a stack overflow in normal operation then you need to think of a different approach to the problem.
It's not difficult to convert a recursive function into an iterative one, especially as C# has the Generic::Stack collection. Using the Stack type moves the memory used into the program's heap instead of the stack. This gives you the full address range to store the recursive data. If that isn't enough, it's not too difficult to page the data to disk. But I'd seriously consider other solutions if you get to this stage.