mirror of
https://github.com/python/cpython.git
synced 2025-10-03 13:45:29 +00:00
The combo of getstate/setstate/jumpahead is very powerful, but needs
examples to flesh it out for the uninitiated. Here they are.
This commit is contained in:
parent
85e2e4742d
commit
e360d9507a
2 changed files with 93 additions and 8 deletions
|
@ -38,11 +38,57 @@ own instances of \var{Random} to get generators that don't share state.
|
||||||
This is especially useful for multi-threaded programs, creating a different
|
This is especially useful for multi-threaded programs, creating a different
|
||||||
instance of \var{Random} for each thread, and using the \method{jumpahead()}
|
instance of \var{Random} for each thread, and using the \method{jumpahead()}
|
||||||
method to ensure that the generated sequences seen by each thread don't
|
method to ensure that the generated sequences seen by each thread don't
|
||||||
overlap. Class \var{Random} can also be subclassed if you want to use a
|
overlap (see example below).
|
||||||
different basic generator of your own devising: in that case, override the
|
Class \var{Random} can also be subclassed if you want to use a different
|
||||||
|
basic generator of your own devising: in that case, override the
|
||||||
\method{random()}, \method{seed()}, \method{getstate()},
|
\method{random()}, \method{seed()}, \method{getstate()},
|
||||||
\method{setstate()} and \method{jumpahead()} methods.
|
\method{setstate()} and \method{jumpahead()} methods.
|
||||||
|
|
||||||
|
Here's one way to create threadsafe distinct and non-overlapping generators:
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
def create_generators(num, delta, firstseed=None):
|
||||||
|
"""Return list of num distinct generators.
|
||||||
|
Each generator has its own unique segment of delta elements
|
||||||
|
from Random.random()'s full period.
|
||||||
|
Seed the first generator with optional arg firstseed (default
|
||||||
|
is None, to seed from current time).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from random import Random
|
||||||
|
g = Random(firstseed)
|
||||||
|
result = [g]
|
||||||
|
for i in range(num - 1):
|
||||||
|
laststate = g.getstate()
|
||||||
|
g = Random()
|
||||||
|
g.setstate(laststate)
|
||||||
|
g.jumpahead(delta)
|
||||||
|
result.append(g)
|
||||||
|
return result
|
||||||
|
|
||||||
|
gens = create_generators(10, 1000000)
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
That creates 10 distinct generators, which can be passed out to 10 distinct
|
||||||
|
threads. The generators don't share state so can be called safely in
|
||||||
|
parallel. So long as no thread calls its \code{g.random()} more than a
|
||||||
|
million times (the second argument to \function{create_generators}), the
|
||||||
|
sequences seen by each thread will not overlap. The period of the
|
||||||
|
underlying Wichmann-Hill generator limits how far this technique can be
|
||||||
|
pushed.
|
||||||
|
|
||||||
|
Just for fun, note that since we know the period, \method{jumpahead()} can
|
||||||
|
also be used to "move backward in time":
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
>>> g = Random(42) # arbitrary
|
||||||
|
>>> g.random()
|
||||||
|
0.24855401895528142
|
||||||
|
>>> g.jumpahead(6953607871644L - 1) # move *back* one
|
||||||
|
>>> g.random()
|
||||||
|
0.24855401895528142
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
|
||||||
Bookkeeping functions:
|
Bookkeeping functions:
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,51 @@
|
||||||
|
|
||||||
Translated from anonymously contributed C/C++ source.
|
Translated from anonymously contributed C/C++ source.
|
||||||
|
|
||||||
Multi-threading note: the random number generator used here is not
|
Multi-threading note: the random number generator used here is not thread-
|
||||||
thread-safe; it is possible that two calls return the same random
|
safe; it is possible that two calls return the same random value. However,
|
||||||
value. But you can instantiate a different instance of Random() in
|
you can instantiate a different instance of Random() in each thread to get
|
||||||
each thread to get generators that don't share state, then use
|
generators that don't share state, then use .setstate() and .jumpahead() to
|
||||||
.setstate() and .jumpahead() to move the generators to disjoint
|
move the generators to disjoint segments of the full period. For example,
|
||||||
segments of the full period.
|
|
||||||
|
def create_generators(num, delta, firstseed=None):
|
||||||
|
""\"Return list of num distinct generators.
|
||||||
|
Each generator has its own unique segment of delta elements from
|
||||||
|
Random.random()'s full period.
|
||||||
|
Seed the first generator with optional arg firstseed (default is
|
||||||
|
None, to seed from current time).
|
||||||
|
""\"
|
||||||
|
|
||||||
|
from random import Random
|
||||||
|
g = Random(firstseed)
|
||||||
|
result = [g]
|
||||||
|
for i in range(num - 1):
|
||||||
|
laststate = g.getstate()
|
||||||
|
g = Random()
|
||||||
|
g.setstate(laststate)
|
||||||
|
g.jumpahead(delta)
|
||||||
|
result.append(g)
|
||||||
|
return result
|
||||||
|
|
||||||
|
gens = create_generators(10, 1000000)
|
||||||
|
|
||||||
|
That creates 10 distinct generators, which can be passed out to 10 distinct
|
||||||
|
threads. The generators don't share state so can be called safely in
|
||||||
|
parallel. So long as no thread calls its g.random() more than a million
|
||||||
|
times (the second argument to create_generators), the sequences seen by
|
||||||
|
each thread will not overlap.
|
||||||
|
|
||||||
|
The period of the underlying Wichmann-Hill generator is 6,953,607,871,644,
|
||||||
|
and that limits how far this technique can be pushed.
|
||||||
|
|
||||||
|
Just for fun, note that since we know the period, .jumpahead() can also be
|
||||||
|
used to "move backward in time":
|
||||||
|
|
||||||
|
>>> g = Random(42) # arbitrary
|
||||||
|
>>> g.random()
|
||||||
|
0.24855401895528142
|
||||||
|
>>> g.jumpahead(6953607871644L - 1) # move *back* one
|
||||||
|
>>> g.random()
|
||||||
|
0.24855401895528142
|
||||||
"""
|
"""
|
||||||
# XXX The docstring sucks.
|
# XXX The docstring sucks.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue