It really depends on the program architecture and what issue you're debugging.
For most single-threaded or simple multithreaded programs, it's easier just to throw a print statement where you need it and analyze that. Even with a large data set, a simple grep will probably get you what you need.
When you're debugging a complex, multithreaded program, on the other hand, an external debugger is much more valuable, because you can break at the exact point where things go wrong, and examine the entire program's behavior at that point. Debugging a race condition with prints can be pretty difficult, especially when the printing changes the timings of the threads.
I've debugged my fair shared of parallel programs (multithreaded and distributed), and I've used a mix of both techniques. The advantage to print statements is that it gives you an execution trace. It's easier for me to reconstruct the sequence of events - which is not trivial in a parallel program. What I give up is full knowledge of any one instant. And that's what a debugger gives me.
It's a trade-off, but I usually start with traces.
I've been debugging plenty of distributed/parallel processing systems by trace statements. It's not trivially easy, but its not too bad (its actually kind of fun).
In fact, I'm not exactly sure how you would debug a multi-process parallel system with an external debugger. Would you simultaneously use multiple debugger instances to attach to each process? That sounds like fun.
For a true, parallel system it's virtually impossible to "examine the entire program's behavior" at any one instance in time. Sure printing changes the timing of things, but unless you are single threaded, you are kidding yourself to think that a debugger also doesn't disrupt timings.
For most single-threaded or simple multithreaded programs, it's easier just to throw a print statement where you need it and analyze that. Even with a large data set, a simple grep will probably get you what you need.
When you're debugging a complex, multithreaded program, on the other hand, an external debugger is much more valuable, because you can break at the exact point where things go wrong, and examine the entire program's behavior at that point. Debugging a race condition with prints can be pretty difficult, especially when the printing changes the timings of the threads.