5 ms·
> Which specific code did you benchmark? I had a csv file with ~16k entries. Each entry has a lat, lon, name and id. The task: given a (lat, lon) pair, list a
by hasenj 9y ago
> Which specific code did you benchmark?
I had a csv file with ~16k entries. Each entry has a lat, lon, name and id.
The task: given a (lat, lon) pair, list all entries within 5km.
The simplest straight forward solution is to iterate the list, measure the distance of each item to the given point, and add it to the return list if the distance is within the desired range.
No crazy optimization or anything.
The results were something roughly like this:
The D version runs in 2~4ms when compiled with optimizations turned on to the max, and about 6~8ms without optimizations (just default compiler settings).
The Go version runs in about 6~8ms. (The Go compiler has no option to produce optimized code).
The python version runs in about 50ms.
That's 10x slower than Go and 20x slower than D.
This is python 3. Using pypy shows absolutely no difference in performance.
Obviously the time to load the data from the csv file into a list is not counted in the above results.
> I’ve seen multiple cases where Python beat C/Go because the app used something like dictionaries which was heavily optimized C code in the standard library.
That's exactly backwards.
The Go and D versions use structs which are compact data structures that pack the data together. So the entire array fits in one contiguous block of memory.
Python has no concept of structs, so you have to deal with dictionaries.
In general, writing optimized code is not a good idea. You should almost always write the most plain and straight forward code.
Because fast languages are fast by default, there's no optimization required. The straight forward solution is fast enough.
If you are writing Python, your code will be slow by default. You will need to think about ways to optimize it if you want better performance.
- weberc2 9y agoWorth noting that Python's csv library is optimized C, and it handily beats Go's so this benchmark must be dominated by non-CSV parsing.
- hasenj 9y agoThe csv parsing is not part of the benchmark. The only thing I measured is iterating the list and matching entries within range of the input coordinate.
- maxerickson 9y agoPeople talk about numpy as a numerical library, another way to think of it is as an api for interacting with contiguous chunks of memory.
- deleted 9y ago[deleted]
- tychver 9y agoThe whole Ruby VM only takes ~50ms to start, so that sounds a bit slow. I wrote a quick version in Ruby and it only takes 5ms: https://gist.github.com/jamatthews/d910a2b39c87a871264dd31d13d5db9a https://gist.github.com/jamatthews/d910a2b39c87a871264dd31d1...
- hasenj 9y agoIt's a bit more complicated. I'm measuring geographical distances so I'm using haversine from math import radians, cos, sin, asin, sqrt def distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float: # taken from: https://stackoverflow.com/a/4913653/35364 # convert decimal degrees to radians lon1 = radians(lon1) lon2 = radians(lon2) lat1 = radians(lat1) lat2 = radians(lat2) # haversine formula dlon = lon2 - lon1 dlat = lat2 - lat1 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 c = 2 * asin(sqrt(a)) r = 6371008 # Average radius of earth in meters return c * r
- tychver 9y agoUsing Haversine distance increases it to only 13ms. I'm not sure why your Python implementation is so slow? In the real world, things like haversine are implemented as C extensions, so I wrote one for Ruby as a comparison and it runs in 3.8ms for 16k points. https://gist.github.com/jamatthews/d910a2b39c87a871264dd31d13d5db9a https://gist.github.com/jamatthews/d910a2b39c87a871264dd31d1... The Ruby GIS libaries already have C implementations for haversine but I just wanted to show how easy it is to hook out to a C function for math heavy stuff.
- hasenj 9y agoIt was slow because at first I put the import inside the function. Moving it out improved the python performance to 20ms (as I mentioned in another comment). The javascript version runs in 15ms. > In the real world, things like haversine are implemented as C extensions Having to write C-extensions is, well a point of friction, and adds complexity. If you just used a native language to begin with, the simple straight forward code would work just fine. Btw the source is here, and it also includes the csv file. https://bitbucket.org/hasenj/geodb/src https://bitbucket.org/hasenj/geodb/src
- hasenj 9y agoI cannot edit my previous comment but just now I revisited the code and noticed there was an import inside the function measuring the distance. One I moved the import out of the function, the execution time was cut by a bit more than half, to about 20ms. The go version runs in about 3ms, not 6ms. The D version runs in 2ms. So overall the python version is 10x slower than native, not 20x slower. Which is still kind of bad.