[Numpy-discussion] locking np.random.Generator in a cython nogil context?
Kevin Sheppard
kevin.k.sheppard at gmail.com
Mon Dec 14 08:45:52 EST 2020
You need to reacquire the gil, then you can get the lock and rerelease the
gil.
I think this works (on phone, so untested)
with gil:
with nogil, lock:
...
Kevin
On Mon, Dec 14, 2020, 13:37 Evgeni Burovski <evgeny.burovskiy at gmail.com>
wrote:
> Hi,
>
> What would be the correct way of locking the bit generator of
> np.random.Generator in cython's nogil context?
> (This is threading 101, surely, so please forgive my ignorance).
>
> The docs for extending np.random.Generator in cython
> (https://numpy.org/doc/stable/reference/random/extending.html#cython)
> recommend the following idiom for generating uniform variates, where
> the GIL is released and a Generator-specific lock is held:
>
> x = PCG64()
> rng = <bitgen_t *> PyCapsule_GetPointer(x.capsule, capsule_name)
> with nogil, x.lock:
> rng.next_double(rng.state)
>
> What is the correct way of locking it when already in the nogil
> section (so that x.lock is not accessible)?
>
> The use case is a long-running MC process which generates random
> variates in a tight loop (so the loop is all nogil). In case it
> matters, I probably won't be using python threads, but may use
> multiprocessing.
>
> Basically,
>
> cdef double uniform(self) nogil:
> if self.idx >= self.buf.shape[0]:
> self._fill()
> cdef double value = self.buf[self.idx]
> self.idx += 1
> return value
>
> cdef void _fill(self) nogil:
> self.idx = 0
> # HERE: Lock ?
> for i in range(self.buf.shape[0]):
> self.buf[i] = self.rng.next_double(self.rng.state)
>
>
> Thanks,
> Evgeni
>
>
> P.S. The full cdef class, for completeness:
>
> cdef class RndmWrapper():
> cdef:
> double[::1] buf
> Py_ssize_t idx
> bitgen_t *rng
> object py_gen # keep the garbage collector away
>
> def __init__(self, seed=(1234, 0), buf_size=4096, bitgen_kind=None):
> if bitgen_kind is None:
> bitgen_kind = PCG64
>
> # cf Numpy-discussion list, K.~Sheppard, R.~Kern, June 29,
> 2020 and below
> #
> https://mail.python.org/pipermail/numpy-discussion/2020-June/080794.html
> entropy, num = seed
> seed_seq = SeedSequence(entropy, spawn_key=(num,))
> py_gen = bitgen_kind(seed_seq)
>
> # store the python object to avoid it being garbage collected
> self.py_gen = py_gen
>
> capsule = py_gen.capsule
> self.rng = <bitgen_t *>PyCapsule_GetPointer(capsule, capsule_name)
> if not PyCapsule_IsValid(capsule, capsule_name):
> raise ValueError("Invalid pointer to anon_func_state")
>
> self.buf = np.empty(buf_size, dtype='float64')
> self._fill()
>
> @cython.boundscheck(False)
> @cython.wraparound(False)
> cdef void _fill(self) nogil:
> self.idx = 0
> for i in range(self.buf.shape[0]):
> self.buf[i] = self.rng.next_double(self.rng.state)
>
> @cython.boundscheck(False)
> @cython.wraparound(False)
> cdef double uniform(self) nogil:
> if self.idx >= self.buf.shape[0]:
> self._fill()
> cdef double value = self.buf[self.idx]
> self.idx += 1
> return value
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at python.org
> https://mail.python.org/mailman/listinfo/numpy-discussion
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.python.org/pipermail/numpy-discussion/attachments/20201214/776e4fa5/attachment.html>
More information about the NumPy-Discussion
mailing list