Next step is trying alternative approach, but if that alternative doesn't work I'm going to see about wrapping your package for Python.
Thanks for all your work on it!
5,611 karma · joined February 24, 2016
I write about fundamental engineering skills and programmer career advice at https://codewithoutrules.com
I also write a weekly email about all the mistakes I've made both coding and in my career over the past 20 years, so that you can learn and avoid them: https://softwareclown.com
Next step is trying alternative approach, but if that alternative doesn't work I'm going to see about wrapping your package for Python.
Thanks for all your work on it!
In general I suspect it's the usual "NumPy arrays are fast, everything else you better be getting a sufficiently large boost from the low-level code to justify conversion".
For the thing I prototyped in Rust, it was wrapping the `ahocorasick` crate which was in fact faster than `pyahocorasick` which is written in C or Cython or something. Both have similar conversion costs, probably, so it came down to "for lots of data the Rust version was faster".
Now I'm starting to use it as part of the Python memory profiler I'm working on (https://pythonspeed.com/fil), in this case to call in to the low-level Python C API which PyO3 includes bindings for in addition to its high-level API. This kind of usage is more like writing C, except with the benefit of having high-level APIs (for GIL holding, but also object conversion) available when I need it.
So basically you get safe, high-level, easy-to-use APIs, with fallback to low-level unsafe APIs if you need them.
Highly recommend trying it out.
1. Figure out what the project's contribution guidelines are.
2. Check out code, figure out how to build it and run tests.
3. If it's a complex task, might want to build some credibility with maintainers first, so might contribute tiny fix first.
4. If it's a complex task, try to engage maintainers to see if they'll accept it, and to get hints on how to approach it. They may be hard to reach, so this might take a few days or a couple of weeks, though I'm not working during that time, it's just delay.
5. Do the actual work.
6. Go through whatever code review process. Sometimes I might need to gently ask for reviews if it sits for too long.
$80 total for all the above is laughable. And to be fair I ask for a good amount of money because I am good at what I do, and there are people who live in much cheaper places than Boston area and could charge less.
For $80, you'd have to both have an extremely low cost of living and already be an expert on the project for this to be in any way worthwhile.
E.g. https://www.theguardian.com/us-news/2021/jan/10/hang-mike-pe...
There's a bit in the Metaflow docs that talks about choosing resources, like RAM: "as a good measure, don't request more resources than what your workflow actually needs. On the other hand, never optimize resources prematurely."
The problem is that for memory, too little means out-of-memory crashes, so the tendency I've seen is to over-provision memory, which ends up getting very expensive at scale.
This choice between "my process crashes" and "I am incentivized to make my process organizationally expensive" isn't ideal. Do you have any ways you deal with this at Netflix, or have you seen ways other Metaflow users deal with it?
I have some ideas on how this could be made better (some combination of being able to catch OOM situations deterministically, memory profiling, and sizing RAM by input size for repeating batch jobs), based in part on some tooling I've been working on for memory profiling: https://pythonspeed.com/fil, so would love to talk about it if you're interested.
And even if you return memory to the OS, that doesn't actually solve too-high memory usage.
Some things you can do:
The article mentions `__slots__` for reducing object memory use, and other approaches include just having fewer objects: for example, a dict of lists uses far less memory than a list of dicts with repeating fields. And you can also in many cases switch to a dataframe with Pandas, saving even more memory (https://pythonspeed.com/articles/python-object-memory/ covers all of those).
For numeric data, a NumPy array gets rid of the per-integer overhead for Python, so a Python list of numbers use way more memory than an equivalent NumPy array (https://pythonspeed.com/articles/python-integers-memory/).
2. Given you do want system package updates, you need to deal with Docker caching breaking your security updates. So you need to rebuild your image from scratch, without caching, either every time there is a security update or on a weekly basis. https://pythonspeed.com/articles/docker-cache-insecure-image...
3. Not mentioned: don't use build secrets via ARG.
Some approaches to secure build secrets:
1. BuildKit supports them: https://docs.docker.com/develop/develop-images/build_enhance...
2. Via the network, which is a hack, but it works: https://pythonspeed.com/articles/docker-build-secrets/
3. Via multi-stage builds, but this destroys caching.
1. It's easier at existing job; you have all this knowledge that's hard to replace (https://codewithoutrules.com/2019/01/25/4-day-workweek-easy-...).
2. At new jobs, apply normally. Then _after_ you get an offer, ask for shorter hours.
3. I wrote a book about the process; it's no longer public linked on my site because pandemic has lowered negotiation leverage a lot and I'm not sure how to address that, but if you're interested: https://codewithoutrules.com/3dayweekend/
But if you want Python 3.8, the soon-to-be-released Python 3.9, or other versions, you don't have that.
See here for why and how to fix it: https://pythonspeed.com/articles/faster-multi-stage-builds/
Specifically, multi-stage builds let you get better caching and therefore faster rebuilds, since you can cache the pre-installed gcc etc. layer, while still getting the small image.
So if you have a human being waiting on frequent Docker build results, yes, multi-stage is better.
In this case, the builds are automated, no one waits for them, so it doesn't really matter (except for burning some extra CPU cycles).
I would ban someone for that. "Toxic loonytoon" is not a productive way to have a discussion.
(Originally quoted it here but getting formatting right here is terrible).
You start pedaling, and the bike engine helps you, so going up hills is easy.
Riding one feels like you have super-strength.
1. FUSE filesystems. This means sending really slow queries to S3, and so you're much better off using compression to get better performance.
2. Syncing to filesystem with AWS DataSync. This would work, yes, but it's a S3 specific feature and not all blob storage systems have it.
pytables might make it possible though, haven't looked.
My impression from the talk linked in the article was that HDF5 doesn't do BLOSC by default, and that in general it's much easier to plug new things in, add caching, etc..
And for that Dask supports Zarr, and HDF5, and pre-existing arrays (where mmap() comes in), and a few other formats: https://docs.dask.org/en/latest/array-creation.html#