Quite a few years ago I wrote a little Runge-Kutta solver in Perl for some simulation work. It seemed like a good idea at the time. The equations of motion had to be integrated over a very long time, and it could take hours for a single run (still much faster than the Monte Carlo it was being used to do a sanity-check on). I re-wrote everything in C++, and picked up less than a factor of two in speed.
So it isn't that "Python is interpreted" that is the problem, because "Perl is interpreted" in exactly the same way. It really does seem to come down to the Python object model. Perl's scalar types have vastly less overhead, so much so that you can actually do reasonably efficient numerical computation in it.
I abandoned Perl for Python shortly thereafter because once I got over the "oh my god it's full of whitespace" thing Python was just more fun to code in, but the speed that Perl provided is something I've definitely missed, and it was a real awakening to the notion that interpreted languages don't have to be slow. The striking thing was that unlike Java (say) where it can be fast but you generally have to think about it, I was getting fast Perl without even really trying.
For a general-purpose problem, Perl won't be particularly fast. For a Perl-type problem (scanning and parsing big files), Perl is very fast.
Doing a Perl-type problem in a general-purpose language would be considerably slower. However, Python or others will perform much better in the "can I read my own code six months later" benchmark.
I don't know why I always have to chip in on "perl is unreadable lol" comments, but over the last 8 years apart from a steady trickle of C coding here and there the bulk of my dayjob has moved around from C/Verilog, then I discovered Ruby, then Perl/R/Python, to full-time Python now.
It's true that unsupervised, weak coders using perl turn out worse code than in other languages. But it really doesn't take much to produce good code if you have a tiny bit of supervision/discipline (which stems mostly from 80% of perl tutorials on the web are teaching 1997-era perl anti-patterns). And/or if you happen to be a stronger programmer in something else, hopefully you stumble across perlcritic and modern perl patterns more quickly.
Well-written Moose code involves less boilerplate, the declarative nature and composability of classes, types and data members with free type/value validation is a delight to maintain, and results in more robust code with a lot fewer silent failures (or objects happily chugging along silently with invalid state) than typical Python classes.
Of course, now that I can't use Moose and the Python community actively seems to discourage the very thought of relying on any superset of core Python OO features like enthoughts' traits package - I really want to revisit static/stronger typed programming languages for large projects. So it feels like I've come full-circle in my programming career...
If I had to guess speed is pretty close to C, right.
Nim is pretty awesome and has been around for a while. I wish one of big entities out there Google, Mozilla, Microsoft, Apple would have adopted Nim and ran with it instead of inventing their own langauges.
At the time when Go and Rust were conceived Nim would have certainly not been on their radar. Both were announced in 2009, at a time when the Nimrod repository had barely even got off the ground[0]. And Nim doesn't really address one of Apple's chief concerns: smoothly transitioning away from Objective-C.
Those are only checks, and don't make your code faster (in fact, slower, when checks are enabled). To get efficiency benefits you need a language/compiler designed around static typing. Cython offers a superset of Python that can be statically typed.
Last time I used Perl it went badly, but it was a typical hacked up mess.
For someone mainly in the Python/Java/C++ world is Moose something worth looking at as a mind expansion exercise? Your description makes it sound appealing.
I want to write something concise and coherent, but it's not happening today :) Instead, assuming you've read the teasers in the Moose manual [1] I'd recommend this [2] interesting comparison of how horizontal code re-use can be achieved in Java, Ruby, PHP and Perl+Moose. There's more philosophical/winding essays on Moose from Chromatic, for example at [3].
Roles/traits/method modifiers/MOP/composability etc. are all great things for getting more reusability... however (and this might sound stupid) the thing that saddens me most when writing Python code is when I find myself adding a bunch of asserts or adding program logic "manually" in situations where I'd normally specify that sort of thing declaratively in a Moose class definition or by referring to a centrally managed Type or delegate stuff through attribute features.
On the other hand, I'm barely into year 2 of full-time Python dev, so perhaps I've yet to find the idiomatic way of doing Python things I used to take for granted in Moose.
Regarding Perl 6, I don't know much about it, except that the original authors of Moose had some inspiration from it.
Is picking up Perl+Moose mind-expanding? It was for me, but I feel that what Moose gave me in Perl was a bit of a band-aid over the fact that it's such a malleable open-ended dynamic language. So as a C++/Java programmer this aspect might not be so enlightening to you, except to see how Moose achieves it in a pretty painless way that I think is very nice and idiomatic for a dynamic language (with the caveats that brings). To put it another way: it gives Perl some of the great benefits of properly declaring things up-front, without the boilerplate/inflexibility pain that I perceive the Java ecosystem's bureaucracy to be (I haven't touched Java for 10 years, so take that with a grain of salt).
If you want to explore some Moose-ish kinds of things within Python, check out [4] (there's another Moose clone in Python that's similarly inactive, sadly) and [5] (Enthought's stuff is perhaps a bit too heavy and incomplete to be the "Moose of the python world", but it gives you a good idea of some of the nice patterns possible when you think outside of the core Python OO featureset).
One of those times I wish I had more than one upvote - thanks!
I definitely have a preference for a more declarative approach, and not in the J2EE giant piles of XML way. Will give these a look for inspiration - thanks again!
> For a Perl-type problem (scanning and parsing big files), Perl is very fast.
I think it's a matter of what you're comparing it to.
Compared to using Perl for a general-purpose problem, Perl for scanning/parsing is fast.
Compared to scanning/parsing with C, Perl is not fast.
$ ruby -e '1.upto(1000000) { |n| puts "This is line number #{n}" }' > file
$ time perl -ne 'print if /number 12345/' < file
[...]
real 0m0.193s
user 0m0.189s
sys 0m0.004s
$ time grep "number 12345" file
[...]
real 0m0.023s
user 0m0.019s
sys 0m0.005s
I gave Perl every possible advantage here. I didn't actually even write any Perl except a regular expression, which is delegated immediately to C. I didn't even write the loop in Perl, I like the Perl main() function handle that. And still the C program is almost 10x faster.
Note: these test runs are from Linux. On OS X the Perl results were almost the same, but "grep" was unexplainably way slower. It seems to hang after it's already dumped all of its output. Basically grep on OS X appears to be badly broken somehow.
I'm always wary of these kinds of sub-second benchmarks because more often than not you've only accidentally measured just the compilation and startup times.
I might have some bias though from speeding up a crusty old Perl CGI web apps with multi-second request times down to less than 100ms simply by keeping the perl processes persistent with mod_fcgid or whatever.
> I'm always wary of these kinds of sub-second benchmarks because more often than not you've only accidentally measured just the compilation and startup times.
I increased the iteration count by 10x and observed exactly the same pattern:
$ time perl -ne 'print if /number 12345/' < file
[...]
real 0m1.661s
user 0m1.586s
sys 0m0.076s
$ time grep "number 12345" file
[...]
real 0m0.188s
user 0m0.132s
sys 0m0.056s
I recall anecdotal reports that Perl was faster than egrep in some cases. I never tested it myself and that was a long time ago—could be a bug that is long since fixed.
When I have a one-time computation job that takes an hour to write and two hours to run in Perl, but in C takes 10 hours to write and half an hour to run, then Perl is faster than C.
And these one-time/rare/short jobs are much more frequent than intense, high throughput C code like the nginix web server or the node javascript interpreter.
I see your point, C is definitely the choice for long running jobs or jobs that will be run more than a handful of times, in my experience however I'm writing a lot of one-off scripts that take 30 seconds tops to run so Perl wins out pretty hard over C.
What you are seeing is different regex engines and capabilities, and grep's focus on pure speed and optimization of a common case and Perl's focus on versatility.
I see very similar results between Perl and grep, and you can see this by also including egrep, which allows slightly more complex expressions:
[root@stats ~]# time perl -ne 'print if /number 123456/' < /tmp/file
[...]
real 0m1.990s
user 0m1.937s
sys 0m0.049s
[root@stats ~]# time grep "number 123456" /tmp/file
[...]
real 0m0.158s
user 0m0.115s
sys 0m0.035s
[root@stats ~]# time egrep "number 123456" /tmp/file
[...]
real 0m0.150s
user 0m0.127s
sys 0m0.023s
But what happens if we use a slightly more complex expression?
[root@stats ~]# time perl -ne 'print if /number [1]23456/' < /tmp/file
[...]
real 0m1.989s
user 0m1.925s
sys 0m0.047s
[root@stats ~]# time grep "number [1]23456" /tmp/file
[...]
real 0m1.402s
user 0m1.366s
sys 0m0.022s
[root@stats ~]# time egrep "number [1]23456" /tmp/file
[...]
real 0m1.414s
user 0m1.382s
sys 0m0.031s
The difference becomes much less pronounced. What if we make the expression just a bit more complex?
[root@stats ~]# time perl -ne 'print if /number [1]23456[0-9]*/' < /tmp/file
[...]
real 0m1.950s
user 0m1.910s
sys 0m0.039s
[root@stats ~]# time grep "number [1]23456[0-9]*" /tmp/file
[...]
real 0m9.353s
user 0m9.307s
sys 0m0.037s
[root@stats ~]# time egrep "number [1]23456[0-9]*" /tmp/file
[...]
real 0m9.539s
user 0m9.483s
sys 0m0.045s
So, now we have the Perl regex engine fairly static across extra complexity while grep and egrep are seeing order of magnitude time increases, and are much slower than Perl at this point. I suspect your first benchmark was the result of a specific optimization grep has that Perl doesn't, or it may be that grep was able to switch to using a DFA regex for that first case, while Perl doesn't both with a completely different regex implementation for special cases like that.
Anecdata: I needed to process a large amount of XML a while back, to the point where a week spent testing and optimizing XML parsing libraries in Perl was worth it, because it could shave weeks or months off the processing time. The winner? A regex that captured attributes and content and assigned name/value pairs directly out to a hash. This was only possible because the XML was highly normalized, but it was actually over 10 times faster than the closest competitor for XML parsing I could fine, and I checked all the libXML libXML2, and SAX libraries I could get my hands on.
In the end, it was something as simple as the following approximation:
while (my ($doc) = $xml =~ /$get_record_xml_re/) {
my %hash = $get_record_xml =~ /$record_begin_re$capture_name_and_value_pairs_re$record_end_re/;
process_record( \%hash );
}
Your results are interesting and I'd be curious to know why the grep degrades so badly on that last regex.
But the original benchmark was ridiculously biased in favor of Perl by not actually doing anything in Perl.
If Perl is actually being competitive in the unfair benchmark, the benchmark should be made more fair by actually putting some logic in Perl, and writing the equivalent logic in C. At that point, you would start to see C win again (modulo any inherent inefficiencies in grep's regex engine).
> This was only possible because the XML was highly normalized
Another way of putting this is: your regex wasn't actually an XML parser. Things that are actually XML parsers were slower. This is not too surprising.
A 10x slowdown does surprise me somewhat. It doesn't surprise me that you beat libXML or any library that builds the XML structure into a complete DOM before you can process the first record. It does surprise me that you beat SAX by 10x. SAX does have some inefficiency built in, like how it turns attributes into a dictionary internally before giving them to the application. That would probably mean that SAX bindings for Perl to a C parser would have to take a full SAX attribute hash and turn it into a Perl attribute hash. Still, 10x is pretty bad.
> Your results are interesting and I'd be curious to know why the grep degrades so badly on that last regex.
I really do think it has to do with grep swapping out regex implementations based on features needed. The last regex matches a variable length string, so it may trigger a much more complex and/or cpu-intensive regex engine to be used.
> If Perl is actually being competitive in the unfair benchmark, the benchmark should be made more fair by actually putting some logic in Perl, and writing the equivalent logic in C. At that point, you would start to see C win again (modulo any inherent inefficiencies in grep's regex engine).
I see your point, but I think it's less relevant than you suppose. Regular expressions are first class citizens in Perl, just as much as Arrays and Hashes. This doesn't just mean that the syntax has some niceties, but you can actually call Perl code within the regex itself[1], and even use this feature to build a more complex regular expression as you parse[2]. Complaining that Perl uses a regex and it isn't Perl is sort of like complaining Perl is using hashes, and any fair benchmark between C and Perl should just stick to Arrays.
> Another way of putting this is: your regex wasn't actually an XML parser. Things that are actually XML parsers were slower. This is not too surprising.
Yes. I didn't want to give the impression a wrote a general purpose XML parser that beat all the C implementations I could find. I still think it's interesting that well formed regular expressions are performant enough in this circumstance to make them a preferred alternative of the many options. I could have written a simple parser in C that would have been faster, but the solution I ended up with is quite fast, robust, and very, very easy to debug.
> That would probably mean that SAX bindings for Perl to a C parser would have to take a full SAX attribute hash and turn it into a Perl attribute hash. Still, 10x is pretty bad.
I think it's more related to the fact that the actions of the regex parsing implementation when optimized sufficiently is very close in implementation to C code that steps through a char array looking for the record beginning and ending indicators, and for the content between them, and then steps through the record looking for data items and saving the key and value for each. The main benefit of using a regex in Perl is that I get what is probably a fairly close approximation (all things considered) of a C implementation of that without having to write any C, and without having to marshal data back and forth to a library to accomplish it, with very simple and concise code.
There are other tasks which obviously aren't going to be nearly as efficient in Perl, but this exchange was spurred by someone talking about Perl being very fast for a Perl-type problem, which this definitely is.
> I really do think it has to do with grep swapping out regex implementations based on features needed.
That wouldn't explain why one regex engine is 5x faster than another. Only looking at the regex engines themselves would tell you that.
> Complaining that Perl uses a regex and it isn't Perl
I'm not complaining that it uses a regex, I'm complaining that it doesn't do anything else.
A representative Perl program would use regexes and contain some logic that processes the results of those regexes.
> I think it's more related to the fact that the actions of the regex parsing implementation when optimized sufficiently is very close in implementation to C code that steps through a char array
I used to think that, but it is really not true unless your regex engine contains a JIT compiler.
Specialized machine code for a text parser (which is what you would get from writing C) is significantly faster than generic NFA/DFA code. In these tests, an average of 65% of runtime was saved when the regex engine included a JIT (ie. the specialized code was over twice as fast): http://sljit.sourceforge.net/pcre.html
> That wouldn't explain why one regex engine is 5x faster than another. Only looking at the regex engines themselves would tell you that.
It could definitely explain it, but it may not be the best explanation given the facts. I'll definitely concede that it's pure conjecture.
> A representative Perl program would use regexes and contain some logic that processes the results of those regexes.
Sure, depending on what you want to show. Nobody is trying to say Perl is as fast or faster than C, just that relatively, it's fast for the development cost it requires.
>> I think it's more related to the fact that the actions of the regex parsing implementation when optimized sufficiently is very close in implementation to C code that steps through a char array
> I used to think that, but it is really not true unless your regex engine contains a JIT compiler.
I think we're referring to different things, which is mostly my fault for being loose with my terminology. I really only meant close to C in a conceptual manner, which yields some performance benefit by keeping a large chunk of the looping and work storing specific chunks of text low level and in the interpreter. I wasn't trying to imply the regex engine's cost was negligible or the actual machine operations we comparable in a large way.
> > regex parsing implementation when optimized sufficiently is very close in implementation to C code
> I used to think that, but it is really not true unless your regex engine contains a JIT compiler.
The P6 Rules engine is written in NQP so it gets JIT'd on the JVM and MoarVM backends.
Of course it'll be many years before the engine is seriously optimized but it's a good start.
It'll be interesting to see if the code gen of this next gen regexen engine gets good enough in 2015 to make its advantages (most notably the grapheme-by-default design) actually pay dividends.
I think they are a pretty good representation of the performance of doing something directly in the language (as opposed to just calling into lower-level libraries written in a different language).
It's sad that this question hasn't actually even been answered yet.
Some things perl does under the hood to be fast are that integers are (mostly) actually integers under the hood. Arrays are actually arrays under the hood (a fact that makes perl's DBI very fast). And more importantly it has had decades of people trying to make it faster without changing the (sometimes crazy) semantics of the language.
But of course languages with JITs a have massively overtaken it in the performance stakes (PyPy, LuaJIT, and JavaScript). Mostly I think this is a result of lack of funding and huge company spending. Just look at what Facebook have managed to do with PHP.
If you're doing numerical computation Numpy will be extremely fast. Most of it is a thin layer over C code so you get the best of both worlds(unless you're the Numpy maintainers).
Is not. We tested our own code in Perl for doing some text processing in our company.
The result was 89 times slower than our c code, which is not so slow compared with other options, but is slow.
We use a lot of c++ and python, but always for managing encapsulated low level code.
With anything that has to compute intensely, like audio, video or 3d work, the differences are way over 3000 times slower. That is: the computer working for a second or for an hour.
Java is not fast, it has never been. It is not its "forte". You could decide to use java or any high level languages based on its merits, but being fast is not one of them.
It is a good idea to learn assembly and disassembly with the debugger before using high level languages. It gives you the knowledge of what computers are really doing under the hood.
If you only got a 2x speedup there is something wrong. A more usual number for Perl is about 100x slower than C++ for numerical code. Perl isn't very different than Python in this regard. e.g. on the shootout on the n-body benchmark, Perl is about as fast as Python, and 125x slower than C++.
I re-wrote everything in C++, and picked up less than a factor of two in speed.
Don't think it has been mentioned in the other comments, but this could also be a performance problem with your C++ code - possibly in combination with doing something Perl is good at
Quite a few years ago I wrote a little Runge-Kutta solver in Perl for some simulation work. It seemed like a good idea at the time. The equations of motion had to be integrated over a very long time, and it could take hours for a single run (still much faster than the Monte Carlo it was being used to do a sanity-check on). I re-wrote everything in C++, and picked up less than a factor of two in speed.
So it isn't that "Python is interpreted" that is the problem, because "Perl is interpreted" in exactly the same way. It really does seem to come down to the Python object model. Perl's scalar types have vastly less overhead, so much so that you can actually do reasonably efficient numerical computation in it.
I abandoned Perl for Python shortly thereafter because once I got over the "oh my god it's full of whitespace" thing Python was just more fun to code in, but the speed that Perl provided is something I've definitely missed, and it was a real awakening to the notion that interpreted languages don't have to be slow. The striking thing was that unlike Java (say) where it can be fast but you generally have to think about it, I was getting fast Perl without even really trying.