每次调用会更新进程字典里的random_seed变量,这样在同一个进程内每次调用random:uniform()时,随机数种子都不同,所以生成的随机数都不一样(调用完random:uniform()后,可以用get(random_seed)查看更新后的种子值)。
但是如果是不同的进程分别调用random:uniform(),因为随机种子更新的算法是一样的,所以每次各进程的随机数种子也是相同的,从而生成的随机数也是一样的,要想让不同进程生成的随机数不同,要手动为每个进程设置不同的种子,常用的是用erlang:now,比如:
random:seed(erlang:now()),random:uniform().
不过如果每个进程调用random:seed(erlang:now())太接近,种子值会比较接近,生成的随机数也会比较接近,更好的方法是用一个单独的进程来生成种子,保证每次的种子值相差比较大:
Seed = {random:uniform(99999), random:uniform(999999), random:uniform(999999)}
然后每次调用random:uniform()前从该种子生成进程获取最新的种子值,seed()之。
下面为random.erl 的源码:
1 %% 2 %% %CopyrightBegin% 3 %% 4 %% Copyright Ericsson AB 1996-2011. All Rights Reserved. 5 %% 6 %% The contents of this file are subject to the Erlang Public License, 7 %% Version 1.1, (the "License"); you may not use this file except in 8 %% compliance with the License. You should have received a copy of the 9 %% Erlang Public License along with this software. If not, it can be 10 %% retrieved online at http://www.erlang.org/. 11 %% 12 %% Software distributed under the License is distributed on an "AS IS" 13 %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14 %% the License for the specific language governing rights and limitations 15 %% under the License. 16 %% 17 %% %CopyrightEnd% 18 %% 19 -module(random). 20 21 %% Reasonable random number generator. 22 %% The method is attributed to B. A. Wichmann and I. D. Hill 23 %% See "An efficient and portable pseudo-random number generator", 24 %% Journal of Applied Statistics. AS183. 1982. Also Byte March 1987. 25 26 -export([seed/0, seed/1, seed/3, uniform/0, uniform/1, 27 uniform_s/1, uniform_s/2, seed0/0]). 28 29 -define(PRIME1, 30269). 30 -define(PRIME2, 30307). 31 -define(PRIME3, 30323). 32 33 %%----------------------------------------------------------------------- 34 %% The type of the state 35 36 -type ran() :: {integer(), integer(), integer()}. 37 38 %%----------------------------------------------------------------------- 39 40 -spec seed0() -> ran(). 41 42 seed0() -> 43 {3172, 9814, 20125}. 44 45 %% seed() 46 %% Seed random number generation with default values 47 48 -spec seed() -> ran(). 49 50 seed() -> 51 case seed_put(seed0()) of 52 undefined -> seed0(); 53 {_,_,_} = Tuple -> Tuple 54 end. 55 56 57 %% seed({A1, A2, A3}) 58 %% Seed random number generation 59 60 -spec seed({A1, A2, A3}) -> 'undefined' | ran() when 61 A1 :: integer(), 62 A2 :: integer(), 63 A3 :: integer(). 64 65 seed({A1, A2, A3}) -> 66 seed(A1, A2, A3). 67 68 %% seed(A1, A2, A3) 69 %% Seed random number generation 70 71 -spec seed(A1, A2, A3) -> 'undefined' | ran() when 72 A1 :: integer(), 73 A2 :: integer(), 74 A3 :: integer(). 75 76 seed(A1, A2, A3) -> 77 seed_put({(abs(A1) rem (?PRIME1-1)) + 1, % Avoid seed numbers that are 78 (abs(A2) rem (?PRIME2-1)) + 1, % even divisors of the 79 (abs(A3) rem (?PRIME3-1)) + 1}). % corresponding primes. 80 81 82 -spec seed_put(ran()) -> 'undefined' | ran(). 83 84 seed_put(Seed) -> 85 put(random_seed, Seed). 86 87 %% uniform() 88 %% Returns a random float between 0 and 1. 89 90 -spec uniform() -> float(). 91 92 uniform() -> 93 {A1, A2, A3} = case get(random_seed) of 94 undefined -> seed0(); 95 Tuple -> Tuple 96 end, 97 B1 = (A1*171) rem ?PRIME1, 98 B2 = (A2*172) rem ?PRIME2, 99 B3 = (A3*170) rem ?PRIME3, 100 put(random_seed, {B1,B2,B3}), 101 R = B1/?PRIME1 + B2/?PRIME2 + B3/?PRIME3, 102 R - trunc(R). 103 104 %% uniform(N) -> I 105 %% Given an integer N >= 1, uniform(N) returns a random integer 106 %% between 1 and N. 107 108 -spec uniform(N) -> pos_integer() when 109 N :: pos_integer(). 110 111 uniform(N) when is_integer(N), N >= 1 -> 112 trunc(uniform() * N) + 1. 113 114 115 %%% Functional versions 116 117 %% uniform_s(State) -> {F, NewState} 118 %% Returns a random float between 0 and 1. 119 120 -spec uniform_s(State0) -> {float(), State1} when 121 State0 :: ran(), 122 State1 :: ran(). 123 124 uniform_s({A1, A2, A3}) -> 125 B1 = (A1*171) rem ?PRIME1, 126 B2 = (A2*172) rem ?PRIME2, 127 B3 = (A3*170) rem ?PRIME3, 128 R = B1/?PRIME1 + B2/?PRIME2 + B3/?PRIME3, 129 {R - trunc(R), {B1,B2,B3}}. 130 131 %% uniform_s(N, State) -> {I, NewState} 132 %% Given an integer N >= 1, uniform(N) returns a random integer 133 %% between 1 and N. 134 135 -spec uniform_s(N, State0) -> {integer(), State1} when 136 N :: pos_integer(), 137 State0 :: ran(), 138 State1 :: ran(). 139 140 uniform_s(N, State0) when is_integer(N), N >= 1 -> 141 {F, State1} = uniform_s(State0), 142 {trunc(F * N) + 1, State1}.
random:seed 由进程字典put存了随机数,random:uniform则get取了随机数,而它同时又put了新的随机数.
如果一开始直接调用,random:uniform/0, 则一开始 get(random_seed)为undefined,后面每次生产的种子的规则都是根据其业务规则生成。 但如果是 先调用random:seed/1 ,则它先生成了随机种子,put到random_seed 的进程字典中,后面依次调用random:uniform/0的时候,则从random_seed的进程字典中取出随机种子,则不是undefined,后面根据其业务规则,生成随机数.