7 ms·
Reading this, I was interested to see how big the speed difference between Python and PHP is these days, so I tried it like this: min.py: i = 10_000_000
by mg 2y ago
Reading this, I was interested to see how big the speed difference between Python and PHP is these days, so I tried it like this:
min.py:
i = 10_000_000
r = 0
while i>0:
i = i-1
r += min(i,500)
print(r)
min.php:
<?php
$i = 10_000_000;
$r = 0;
while ($i>0) {
$i = $i-1;
$r += min($i,500);
}
print($r);
The results:
time python3 min.py
4999874750
real 0m2.523s
time php min.php
4999874750
real 0m0.333s
Looks like Python is still 8x slower than PHP. Pretty significant.
I ran it with Python 3.11.2 and PHP 8.2.18
- winrid 2y agoThe dynamic aspect of Python is once again probably the major penalty here. One major difference here is that in Python you can overwrite min(), so it has to access this function through more abstraction, but not in PHP. I bet PyPy is close to PHP here however.
- JohnKemeny 2y agoWith pypy, the code runs in 0.226s on my computer. So yes, the comparison of OP is CPython vs PHP.
- mg 2y agoYes, it is CPython. Added data on the PyPy performance to this comment now: https://news.ycombinator.com/item?id=41199431 https://news.ycombinator.com/item?id=41199431
- mg 2y agoYou might be right about the min() call being the major penalty. When I avoid the min() call like this ... min2.py: i = 10_000_000 r = 0 while i>0: i = i-1 if i<500: r += i else : r += 500 print(r) I get a speedup of about 50%: time python3 min2.py 4999874750 real 0m1.338s Still 4x slower than PHP though. With PyPy I get an amazing speedup of 96%: time pypy3 min.py 4999874750 real 0m0.088s 4 times faster than the PHP version! I'm not sure what the state of things is regarding PyPy and running a web application. Doing a bit of googling, it seems that calling C functions from PyPy is slow, so one would have to check if the application uses those (for example to connect to the database).
- eesmith 2y agoFWIW, if I place the code in a function, so that variable lookups are constant-time rather than a dictionary lookup in the module globals, then (on my Mac, with Python 3.12) I get a two-fold speedup. That is: def spam(): t1 = time.time() i = 10_000_000 r = 0 while i>0: i = i-1 if i<500: r += i else : r += 500 t2 = time.time() print(r) print("Time:", t2-t1) reports 0.87 seconds outside a function and 0.43 seconds when inside a function. (Using the shell's time, of course, also includes the Python startup time. When I use it I get 0.94 and 0.49 seconds, indicating a 0.06s startup penalty.)
- mg 2y agoInteresting! Same here. Also with pypy3, putting it in a function about doubles the speed: time pypy3 min_in_function.py 4999874750 real 0m0.045s
- eesmith 2y agoBack in Python 1.x, function locals used a dictionary, just like module globals. This made it possible do to: def f(): from math import * return cos(3.0) https://peps.python.org/pep-0227/#import-used-in-function-scope https://peps.python.org/pep-0227/#import-used-in-function-sc... notes "The language reference specifies that import * may only occur in a module scope. (Sec. 6.11) The implementation of C Python has supported import * at the function scope." Python 2.1 added static nested scopes (see the PEP 227 link), which enabled a much faster locals lookup. With that one case excluded, all of the locals can be determined at parse/byte-compile time, stored in a simple vector, and referenced by offset: >>> z = 0 >>> def f(x): ... y = x + z ... return y * 2 ... >>> import dis >>> dis.dis(f) 1 0 RESUME 0 2 2 LOAD_FAST 0 (x) 4 LOAD_GLOBAL 0 (z) 14 BINARY_OP 0 (+) 18 STORE_FAST 1 (y) 3 20 LOAD_FAST 1 (y) 22 LOAD_CONST 1 (2) 24 BINARY_OP 5 (*) 28 RETURN_VALUE The "LOAD_FAST" uses offset 0 to store "x" and offset 1 to store "y", while "z" required a LOAD_GLOBAL to find z in the globals() dictionary.
- pjmlp 2y agoSmalltalk, SELF and Common Lisp are just as dynamic, with great JIT implementations, their research lies the foundation for all modern JITs in dynamic languages, one of those implementations grew up to become Hotspot. Those systems are image based, at any time, you can eval code, break into the debugger, change code and redo the interrupted code, affecting everything that the JIT already improved on the whole image.
- Too 2y ago3.11? The article explains there are improvements on that specific benchmark in newer versions. Not on the order of magnitude that it would catch up here, but still significant.
- ShinTakuya 2y agoNot to be a stickler, but the only fair benchmark would be to select the most recent stable version of each. Doing so is fairly easy with docker I would think, if you don't wish to modify your system.
- deleted 2y ago[deleted]
- mg 2y agoI wouldn't say you are a stickler. But the most productive addition to the discussion would be to do the benchmark as you see fit and then show us the results.
- ShinTakuya 2y agoVery fair feedback. I'll do so once I'm at a machine!
- deleted 2y ago[deleted]
- fastasucan 2y agoThis is more a measurement of looping, calling the min function and printing than the language itself. All benchmarks is of course that to some degree, but I really don't think this is a good comparison.
- edflsafoiewq 2y agoPython also uses bigints.
- rbanffy 2y agoIf someone writes this same program in COBOL and gets better performance (and I’m sure it would) would we be tempted to write more COBOL code? I wouldn’t.
- silvestrov 2y agoIt's even slower than java compiler and jit combined! Java has never been know to be fast for command line programs. My M1 MacBook: 1.716s for min.py AND 0.295s for javac and 0.067s for running the compiled code. It is a straightforward conversion to java using long for i and r.
- mrguyorama 2y agoI once was using a bunch of handmade python scripts to work with terrain heightmaps and ground terrain textures in an attempt to improve FSX visuals before flight sim 2020 was announced. I had 12Kx12K pixel images of the ground in spring, and wanted to make some winter versions for fun. Some basic toying around showed you could reasonably resample a "snow" texture into these photos wherever you had pixels that were "mostly green", ie grass or trees. I wrote this up in python using the simple PIL python library for working with image data. It took 45 minutes per image. I fired up a text editor and within 30 minutes had a java version of the code, most of that time was spent remembering how to write java. 30 seconds per image. I don't care what nonsensical "optimizations" I could have done, like oh just pull it into numpy arrays and work there, oh PIL is slow for pixel manipulation so don't do that, oh you could rewrite it like X and it will be faster I don't care. The simple, naive, amateurish attempt in Java, a language I hadn't touched in 6 years, blew the pants off of the python version, a language I used at my day job. It took zero more effort to write in java than in python. Python is great for doing simple one off scripts, but it is terrible at actual work. Add to that, the tooling around python is mediocre, and for some reason python programmers don't seem to care, while the tooling around java is so good IDEs basically write all the supposedly awful boilerplate code for you. Stuff that I had to do by hand in python was automated in java.
- glass-z13 2y agoI had a similar experience when i was in highschool and learning python. I wrote a image->ascii image convertor using PIL as you did, one image would take a few hundred ms and it was fine, but as i played with it and added more features/learned more i tried to do it on video frames extracted with ffmpeg and it would take atleast 4x the duration of the video or even more to convert it in ascii video. Few months ago i coded it in go since i got back into programming and it was significantly faster(The overall code was also smaller but maybe that's just because i have a bit more experience now) even tho in both cases the implementations was the most naive one i could come up with, without any optimizations. Edit: I went ahead and tested both, took me 30 mintues to set them with identic parameters on 3602 frames(roughly 1 minute video) Keep in mind that this is just a naive implementation with 2 nested loops itereting in a step of 12 over the pixels of the image, no fancy math or numpy used in the python version. Image for reference[0]. Also keep in mind that the step and length of the ascii charmap used affects performance but here i used a simple one "_^:-=fg#%@" so it's a bit easier for the python code, here are the results on my i7 9th gen laptop 1 Minute video 720p 60fps GO - Execution time: 359647 ms, 5.9 minutes ("asciifying the frames") + 30~ seconds ffmpeg video conversion Python 3.12.3 - Execution time: 0:16:25.002945, minus ~25-30 seconds ffmpeg [0]: https://i.postimg.cc/CK30z1jt/frame-000039.png https://i.postimg.cc/CK30z1jt/frame-000039.png [1]: Video using a more detailed ascii charmap(" .,:;i1tfgLCG08@#") in the go version -> https://streamable.com/7h8jc3 https://streamable.com/7h8jc3
- igouy 2y agoCPython 3.12.3 vs PHP 8.3.7 https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/python3-php.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/...