The premise was to not rewrite everything in rust, but you basically ended up rewriting 90% of it in rust
"It is big and complex and very business critical and highly algorithmic, so that would take ~months of work, ..."
21–30 of 223 posts
The premise was to not rewrite everything in rust, but you basically ended up rewriting 90% of it in rust
"It is big and complex and very business critical and highly algorithmic, so that would take ~months of work, ..."
> The library was already using numpy for a lot of its calculations, so why should we expect Rust to be better? I literally clicked in to read the article to see if they'd mention this:) But... unless I missed it, there wasn't really an answer? I thought numpy does do the heavy lifting in native code, so why is this faster? Does this version just push more of the logic into native code than numpy did?
Just that small change already gives 10x faster performance without ever leaving python/numpy land.
The premise was to not rewrite everything in rust, but you basically ended up rewriting 90% of it in rust
90% of the bottleneck, not 90% of their whole application. The author says that rewriting everything in Rust would have taken months, so the whole application must be huge. "It is big and complex and very business critical and highly algorithmic, so that would take ~months of work, ..."
Why do I need to rewrite in Rust, when I can just use Polars[1] that will cover most usecases [1] https://www.pola.rs/
Making Python (near infinitely) faster by using it as a glue language, and running all the computation outside Python :-P
> The library was already using numpy for a lot of its calculations, so why should we expect Rust to be better? I literally clicked in to read the article to see if they'd mention this:) But... unless I missed it, there wasn't really an answer? I thought numpy does do the heavy lifting in native code, so why is this faster? Does this version just push more of the logic into native code than numpy did?
The slowness comes from the interaction of numpy and a Python object "Polygon", which in not numpy. I suspect that a sufficiently clever coder could have optimized the result without resorting to Rust, but at the cost of a substantial increase in complexity of the codebase. The proposed approach keep the Python code simple (and moves the complexity into having another language to deal with).
diff --git a/poly_match_v1.py b/poly_match_v1.py
index 675c88a..4293a46 100644
--- a/poly_match_v1.py
+++ b/poly_match_v1.py
@@ -1,4 +1,5 @@
from functools import cached_property
+from itertools import compress
from typing import List, Tuple
import numpy as np
from dataclasses import dataclass
@@ -56,11 +57,8 @@ def generate_example() -> Tuple[List[Polygon], List[np.array]]:
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)
10x faster than the original, without resorting to native code, and without substantial increase in complexity of code base.Earlier quoted context omitted.
90% of the bottleneck, not 90% of their whole application. The author says that rewriting everything in Rust would have taken months, so the whole application must be huge. "It is big and complex and very business critical and highly algorithmic, so that would take ~months of work, ..."
OP fully rewrote the example program in rust, by also moving the entire data structures there. This would mean that any interaction with these ndarrays could be possible only on the rust side, hence any other code that uses them must be rewritten, unless there’s some porting of rust ndarrays to python numpy ndarrays
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::prelude::*;
use ndarray_linalg::Norm;
use numpy::PyReadonlyArray1;
#[pyfunction]
fn find_close_polygons(
py: Python,
polygons: Vec,
point: PyReadonlyArray1,
max_dist: f64,
) -> PyResult> {
let mut close_polygons = vec![];
let point = point.as_array();
for poly in polygons {
let center = poly
.getattr(py, "center")?
.extract::>(py)?
.as_array()
.to_owned();
if (center - point).norm()
Why is the Rust version 13x faster than the Python version?Making Python (near infinitely) faster by using it as a glue language, and running all the computation outside Python :-P
Yeah what's wrong with that? I think this sounds amazing. It gives you all the fast prototyping and simplicity of Python, but once you hit that bottleneck all you have to do is bring in a ringer to replace key components with a faster language. No need to use Golang or Rust from the start, no need for those resources until you absolutely need the speed improvement. Sounds like a dream to a lot of people who find it m…
The more ML I do, the more disappointed I get.