BitGenerator support - #499
Conversation
Icxolu
left a comment
There was a problem hiding this comment.
This looks like a useful addition! Thanks for working on it. I'm definitely not an expert here, but I left a few comment about things that stood out to me. Let me know what you think.
Also, are there any differences between numpy v1 and v2 that we need to consider?
# Conflicts: # Cargo.toml
|
OK, done. UB fixedturns out the double locking issue fixed@Icxolu as you found in #499 (comment), the lock is re-entrant, so now we just keep a HashSet of locked bitgens so same-thread guards are unique. PS: MSRV is 1.83, and in 1.84 |
|
And done! Please take a look! @Icxolu I followed your initial advice and converted it from a I have gathered some experience using numpy’s generators and figured that using outstanding questions & tasks
|
|
Thanks for picking this back up! It might take me a bit to get my head back into this, but I will try to give this a read as soon as I find some time. |
|
I’m quite happy with it now :D Only caveat (apart from naming): There’s a lot of nit-picking possible with the |
| pub fn into_shared(self) -> Py<PyBitGenerator> { | ||
| self._bit_generator | ||
| } |
There was a problem hiding this comment.
could alternatively be an Into implementation.
Icxolu
left a comment
There was a problem hiding this comment.
I gave this a first pass. For now I mostly looked at the technical stuff and did not really think hard about naming etc. Unfortunately I think there is still a potential soundness issue with lock, see that comment for more details. I believe spawn does not have the same issue, so even if we can't get lock working, this one should be possible.
|
OK, all addressed! I removed the 3.9 gating as asked, so CI fails now, maybe I should put it back until the CI for 3.8 is removed? To have |
See
Fixes #498
The idea is to have a safe wrapper around the
npy_bitgenstruct that implementsrand::RngCore. That way pyo3 functions could be passed anp.random.Generator, get that wrapper from it, and pass it to Rust APIs, which could then call its methods repeatedly.The way it’s implemented, the workflow would look like this:
castanp.random.BitGeneratorinstance into anumpy::random::PyBitGenerator..lock()on it to get anumpy::random::PyBitGeneratorGuard.TODO:
Safety
If somebody releases the threading lock of the
BitGeneratorwhile we’re using it, this isn’t safe 🤔API design options
I could make this more complex by adding a new trait that is implemented by both
PyBitGeneratorandPyBitGeneratorGuard, allowing to choose if someone wants toPyBitGenerator’srandom_*methods directly on that object while holding the GIL and without locking itnp.random.BitGeneratorand returning a GIL-free object that can be used.but for now I just implemented the use case that’s actually desired.