|
25 | 25 |
|
26 | 26 | Translated from anonymously contributed C/C++ source. |
27 | 27 |
|
28 | | -Multi-threading note: the random number generator used here is not |
29 | | -thread-safe; it is possible that two calls return the same random |
30 | | -value. But you can instantiate a different instance of Random() in |
31 | | -each thread to get generators that don't share state, then use |
32 | | -.setstate() and .jumpahead() to move the generators to disjoint |
33 | | -segments of the full period. |
| 28 | +Multi-threading note: the random number generator used here is not thread- |
| 29 | +safe; it is possible that two calls return the same random value. However, |
| 30 | +you can instantiate a different instance of Random() in each thread to get |
| 31 | +generators that don't share state, then use .setstate() and .jumpahead() to |
| 32 | +move the generators to disjoint segments of the full period. For example, |
| 33 | +
|
| 34 | +def create_generators(num, delta, firstseed=None): |
| 35 | + ""\"Return list of num distinct generators. |
| 36 | + Each generator has its own unique segment of delta elements from |
| 37 | + Random.random()'s full period. |
| 38 | + Seed the first generator with optional arg firstseed (default is |
| 39 | + None, to seed from current time). |
| 40 | + ""\" |
| 41 | +
|
| 42 | + from random import Random |
| 43 | + g = Random(firstseed) |
| 44 | + result = [g] |
| 45 | + for i in range(num - 1): |
| 46 | + laststate = g.getstate() |
| 47 | + g = Random() |
| 48 | + g.setstate(laststate) |
| 49 | + g.jumpahead(delta) |
| 50 | + result.append(g) |
| 51 | + return result |
| 52 | +
|
| 53 | +gens = create_generators(10, 1000000) |
| 54 | +
|
| 55 | +That creates 10 distinct generators, which can be passed out to 10 distinct |
| 56 | +threads. The generators don't share state so can be called safely in |
| 57 | +parallel. So long as no thread calls its g.random() more than a million |
| 58 | +times (the second argument to create_generators), the sequences seen by |
| 59 | +each thread will not overlap. |
| 60 | +
|
| 61 | +The period of the underlying Wichmann-Hill generator is 6,953,607,871,644, |
| 62 | +and that limits how far this technique can be pushed. |
| 63 | +
|
| 64 | +Just for fun, note that since we know the period, .jumpahead() can also be |
| 65 | +used to "move backward in time": |
| 66 | +
|
| 67 | +>>> g = Random(42) # arbitrary |
| 68 | +>>> g.random() |
| 69 | +0.24855401895528142 |
| 70 | +>>> g.jumpahead(6953607871644L - 1) # move *back* one |
| 71 | +>>> g.random() |
| 72 | +0.24855401895528142 |
34 | 73 | """ |
35 | 74 | # XXX The docstring sucks. |
36 | 75 |
|
|
0 commit comments