2025, Nov 26 19:00
Reuse a preallocated NumPy buffer for random numbers: in-place batches with Generator.standard_normal
Learn how to generate NumPy random numbers in batches without allocations: reuse a preallocated buffer via Generator.standard_normal(out) for in-place writes.
When you need a stream of random numbers in batches and only one batch is used at a time, repeatedly creating fresh arrays becomes wasteful. The usual call returns a new array on every iteration, which is the opposite of what you want if the goal is to reuse a preallocated buffer.
Baseline that triggers the issue
The straightforward way allocates a new array on each call. That’s convenient, but not ideal for tight loops where you want to avoid churn.
import numpy as npx
items = 1000
# This creates a new array every time
chunk = npx.random.randn(items)
Trying to pass an out argument to this call is not an option, because this form does not support it. Assigning into a preallocated array with a slice, like filling a buffer from a newly generated array, still creates the temporary on the right-hand side, so it doesn’t solve the allocation problem either.
What is actually going on
The generator that returns values from the old call produces a fresh array by design. If your aim is to fill an existing array in-place, you need an API that accepts a target buffer. There is one that does precisely this. It lets you hand over a preallocated array and repopulate it with new samples without allocating a new one for every batch.
There is also a performance nuance. The basic call is rather slow, while the method on a Generator object is apparently significantly faster. Even so, the operation is compute-bound. On one setup (i5-9600KF with 2x3600MHz DDR4), using in-place operations was only about 15% faster, and a larger win might show up in parallel code that calls the generator in each thread.
A practical fix with buffer reuse
The approach below reuses the same buffer and avoids reallocation, batch after batch.
import numpy as npx
prng = npx.random.default_rng()
length = 1000
buf = npx.empty(length)
prng.standard_normal(length, out=buf)
This fills buf in-place. You can repeat the last line whenever you need a fresh batch; the same array will be overwritten with new random values each time.
Why this matters
When you only need one batch in memory at a time, reusing a preallocated array keeps the workflow focused on computation instead of allocation. The method that writes directly into your buffer avoids creating throwaway arrays, and it is also faster than the basic alternative. While the overall task remains compute-bound, this in-place pattern is a clean way to minimize overhead. If you drive this from multiple threads and call the generator in each thread, the improvement can be more pronounced.
Takeaways
For batch-wise random number generation where you want to reuse memory, prefer calling the Generator’s standard_normal with an out buffer. It replaces repeated allocation with deliberate buffer reuse, aligns with the goal of accessing only one batch at a time, and offers measurable speed benefits in practice, even if modest on a single thread.