Making Python faster with Rust
111–120 of 223 posts
Re: Making Python faster with Rust
#112Earlier quoted context omitted.
Python's for loop implementation is slow, also. You can use built in utils like map() which are "native" and can be a lot faster than a for loop with a push: https://levelup.gitconnected.com/python-performance-showdown...
I don't think it's the loop implementation. The stuff in the loop should take multiple orders of magnitude more time than the loop itself: for poly in polygon_subset: if np.linalg.norm(poly.center - point)
Re: Making Python faster with Rust
#113Language design request: Take from Rust Algebraic types, ahead of time compilation and strong types, functional features, a borrow / escape checker that automatically turns shared data into Rc or Arc, as necessary, instead of tormenting me to rewrite performance irrelevant code; Take from Python the simple syntax, default pass by reference of all non-numeric types, simplified string handling, unified slice and array…
Re: Making Python faster with Rust
#114A vectorized implementation of find_close_polygons wouldn't be very complex or hard to maintain at all, but the authors would also have to ditch their OOP class based design, and that's the real issue here. The object model doesn't lend itself to performant, vectorized numpy code.
Re: Making Python faster with Rust
#115I think a big mistake in the article, in a context where performance is the main objective, is that the author uses an array of structs (AoS), rather than a struct of arrays (SoA). An SoA makes it so that the data is ordered contiguously, which is easy to read for the CPU, while an AoS structure interleaves different data (namely the x and y in this case), which is very annoying for the CPU. A CPU likes to read chunk…
Re: Making Python faster with Rust
#116Using PyPy, which is a real compiler, might help. That's doing spatial data processing by exaustive search, which is inherently slow. There are better algorithms. If the number of items to be searched is large, the spatial indices of MySQL could help.
Re: Making Python faster with Rust
#117The most important part of the article seems to be that this Python code is taking "an avg of 293.41ms per iteration": def find_close_polygons( polygon_subset: List[Polygon], point: np.array, max_dist: float ) -> List[Polygon]: close_polygons = [] for poly in polygon_subset: if np.linalg.norm(poly.center - point) And after replacing it with this Rust code, it is taking "an avg of 23.44ms per iteration": use pyo3::pre…
import numpy as np
n_sides = 30
n_polygons = 10000
class Polygon:
def __init__(self, x, y):
self.x = x
self.y = y
self.center = np.array([self.x, self.y]).mean(axis=1)
def find_close_polygons(
polygon_subset: List[Polygon], point: np.array, max_dist: float
) -> List[Polygon]:
close_polygons = []
for poly in polygon_subset:
if np.linalg.norm(poly.center - point)
(I've made up number of sides and number of polygons to get to the same order of magnitude of runtime; also I've pre-computed centers, as they are cached anyway in their code), which on my machine takes about 40ms to run. If we just change the function to: def find_close_polygons(
polygon_subset: List[Polygon], point: np.array, max_dist: float
) -> List[Polygon]:
centers = np.array([polygon.center for polygon in polygon_subset])
mask = np.linalg.norm(centers - point[None], axis=1)
then the same computation takes 4ms on my machine.Doing a Python loop of numpy operations is a _bad_ idea... The new code hardly even takes more space than the original one.
(as someone else mentioned in the comments, you can also directly use the sum of the squares rather than `np.linalg.norm` to avoid taking square roots and save a few microseconds more, but well, we're not in that level of optimization here)
Re: Making Python faster with Rust
#118A vectorized implementation of find_close_polygons wouldn't be very complex or hard to maintain at all, but the authors would also have to ditch their OOP class based design, and that's the real issue here. The object model doesn't lend itself to performant, vectorized numpy code.
What's a good guide to learn how to make (and see) vectorized code? It's a mindshift and not one I find easy.
Numpy's tutorial for broadcasting is also a good starting point.
Re: Making Python faster with Rust
#119This was a silly and unnecessary optimization. He’s just using numpy wrong. Instead of: for p in ps: norm(p.center - point) You should do: centers = np.array([p.center for p in ps]) norm(centers - point, axis=1) You’ll get your same speed up in 2 lines without introducing a new dependency
There's also a "v1.5" version which is 6x faster, and uses "vectorizing" (doing more of the work directly in numpy). This version is much harder to optimize further.
[0] https://github.com/ohadravid/poly-matchRe: Making Python faster with Rust
#120Earlier quoted context omitted.
I don't think it's the loop implementation. The stuff in the loop should take multiple orders of magnitude more time than the loop itself: for poly in polygon_subset: if np.linalg.norm(poly.center - point)
I don’t know if numpy fixed this, but it used to be that mixing Python numbers with numpy in a tight loop is horribly slow. Try hoisting max_dist out of the loop and replacing it with max_dist_np that converts it to a numpy float once.
for x in numpy.array:
is 9X slower than for x in numpy.array.tolist():
in 2021.