如何在分叉进程中获取随机数?
How to get random number in forked processes?
我分叉了几个进程,我需要每个进程对随机选择的项目执行一项任务。
我发现分叉进程选择完全相同的随机数。
我尝试生成种子并调用 srand(),但没有太大帮助。实际上,我读过的大多数文档都建议避免使用 srand() "unless you know exactly what you're doing"。
这是我的代码:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
use Time::HiRes qw(time);
use MongoDB;
#use Math::Random::Secure qw(rand);
my $num_clients = shift;
my $num_loops = 50_000_000;
sub test_forked_sub {
my $sum=0;
my $random_offset = rand(120);
printf "time: %10.4f - Random offset: %6.2f at pid: %s \n", time(), $random_offset, $$;
for (my $i=0; $i < $num_loops ; $i++) {
$sum += rand(120);
}
}
my $nub_processes = 0;
for (my $client_id =0; $client_id < $num_clients; $client_id++ ) {
if (my $pid = fork) { #Parent
$nub_processes++;
}
else { # child
die "cannot fork: $!" unless defined $pid;
test_forked_sub();
exit(0);
}
}
while ($nub_processes){
wait;
$nub_processes--;
}
当我 运行 它时,我在每个进程中得到完全相同的 "random" 数字:
$ time ./test_rand_fork.pl 10
time: 1569510011.6891 - Random offset: 46.64 at pid: 2091
time: 1569510011.6937 - Random offset: 46.64 at pid: 2092
time: 1569510011.6987 - Random offset: 46.64 at pid: 2093
time: 1569510011.7028 - Random offset: 46.64 at pid: 2094
time: 1569510011.7070 - Random offset: 46.64 at pid: 2095
time: 1569510011.7097 - Random offset: 46.64 at pid: 2096
time: 1569510011.7144 - Random offset: 46.64 at pid: 2097
time: 1569510011.7203 - Random offset: 46.64 at pid: 2098
time: 1569510011.7230 - Random offset: 46.64 at pid: 2099
time: 1569510011.7249 - Random offset: 46.64 at pid: 2100
real 0m3.974s
user 0m32.955s
sys 0m1.444s
一个可能但丑陋的解决方案,不要分叉。相反,从我的 shell 到 运行 多个实例如下:
# shell processes
$ for i in `seq 1 10`; do ./test_rand_fork.pl 1 & done
time: 1569511908.7708 - Random offset: 7.44 at pid: 4129
time: 1569511908.8070 - Random offset: 19.50 at pid: 4131
time: 1569511908.8068 - Random offset: 97.59 at pid: 4132
time: 1569511908.8073 - Random offset: 14.51 at pid: 4133
time: 1569511908.8077 - Random offset: 16.70 at pid: 4134
time: 1569511908.8080 - Random offset: 108.63 at pid: 4138
time: 1569511908.8079 - Random offset: 69.44 at pid: 4137
time: 1569511908.8080 - Random offset: 83.25 at pid: 4136
time: 1569511908.8080 - Random offset: 43.33 at pid: 4135
time: 1569511908.8203 - Random offset: 33.82 at pid: 4139
由于 "shell processes" 是一个丑陋的解决方案,我尝试使用 Math::Random::Secure。
这是我根据需要获得随机性的结果,但它比 "shell processes" 方法慢 50 倍:
# using: Math::Random::Secure qw(rand);
$ time ./test_rand_fork.pl 10
time: 1569510036.9331 - Random offset: 112.48 at pid: 2128
time: 1569510036.9470 - Random offset: 47.15 at pid: 2129
time: 1569510036.9501 - Random offset: 20.77 at pid: 2130
time: 1569510036.9517 - Random offset: 40.98 at pid: 2131
time: 1569510036.9521 - Random offset: 13.84 at pid: 2132
time: 1569510036.9538 - Random offset: 20.43 at pid: 2133
time: 1569510036.9543 - Random offset: 48.48 at pid: 2134
time: 1569510036.9563 - Random offset: 109.29 at pid: 2135
time: 1569510036.9579 - Random offset: 70.30 at pid: 2136
time: 1569510036.9601 - Random offset: 24.31 at pid: 2137
real 3m17.251s
user 32m31.129s
sys 0m1.054s
我需要的随机性不是为了安全起见,我只是需要一个好的传播。
有没有办法为分叉进程生成足够好的种子,并且仍然使用标准的 rand() 或更快的替代方法?或者至少不需要安装额外库的东西?
确实是srand你想要的。虽然确实通常不需要乱用它,但有一些用途
However, there are a few situations where programs are likely to want to call srand
. One is for generating predictable results, generally for testing or debugging. There, you use srand($seed)
, with the same $seed
each time.
而且,正是为了您的目的
Another case is that you may want to call srand
after a fork
to avoid child processes sharing the same seed value as the parent (and consequently each other).
一个简单的例子
perl -wE'
say "Parent $$ rand: ", rand;
for (1..4) {
$pid = fork // die "Cant fork: $!";
if ($pid == 0) { srand(); say "\tchild $$ rand: ", rand; exit }
}'
版画
Parent 23375 rand: 0.502774688721733
child 23376 rand: 0.914527430039929
child 23377 rand: 0.97985713889739
child 23378 rand: 0.127702740327553
child 23379 rand: 0.187181734786467
正是上面的 srand
起作用了;没有它,数字是相同的(因为它们必须是)。请注意,它也可以 运行 带有种子,这使我们可以更好地 diagnostic/testing 控制。
注意,避免传播坏习惯。
在上面的快速程序中,子进程被系统清理(由 init 回收)。然而,一个人真的应该总是收获所以上面真的应该
for (1..4) {
$pid = fork // die "Cant fork: $!";
if ($pid == 0) { srand(); say "\tchild $$ rand: ", rand; exit }
push @procs, $pid;
}
for (@procs) { $gone = wait; say "$gone exited with $?" }
waitpid and non-blocking for better monitoring, and perhaps in a signal handler 更好。
我分叉了几个进程,我需要每个进程对随机选择的项目执行一项任务。 我发现分叉进程选择完全相同的随机数。 我尝试生成种子并调用 srand(),但没有太大帮助。实际上,我读过的大多数文档都建议避免使用 srand() "unless you know exactly what you're doing"。
这是我的代码:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
use Time::HiRes qw(time);
use MongoDB;
#use Math::Random::Secure qw(rand);
my $num_clients = shift;
my $num_loops = 50_000_000;
sub test_forked_sub {
my $sum=0;
my $random_offset = rand(120);
printf "time: %10.4f - Random offset: %6.2f at pid: %s \n", time(), $random_offset, $$;
for (my $i=0; $i < $num_loops ; $i++) {
$sum += rand(120);
}
}
my $nub_processes = 0;
for (my $client_id =0; $client_id < $num_clients; $client_id++ ) {
if (my $pid = fork) { #Parent
$nub_processes++;
}
else { # child
die "cannot fork: $!" unless defined $pid;
test_forked_sub();
exit(0);
}
}
while ($nub_processes){
wait;
$nub_processes--;
}
当我 运行 它时,我在每个进程中得到完全相同的 "random" 数字:
$ time ./test_rand_fork.pl 10
time: 1569510011.6891 - Random offset: 46.64 at pid: 2091
time: 1569510011.6937 - Random offset: 46.64 at pid: 2092
time: 1569510011.6987 - Random offset: 46.64 at pid: 2093
time: 1569510011.7028 - Random offset: 46.64 at pid: 2094
time: 1569510011.7070 - Random offset: 46.64 at pid: 2095
time: 1569510011.7097 - Random offset: 46.64 at pid: 2096
time: 1569510011.7144 - Random offset: 46.64 at pid: 2097
time: 1569510011.7203 - Random offset: 46.64 at pid: 2098
time: 1569510011.7230 - Random offset: 46.64 at pid: 2099
time: 1569510011.7249 - Random offset: 46.64 at pid: 2100
real 0m3.974s
user 0m32.955s
sys 0m1.444s
一个可能但丑陋的解决方案,不要分叉。相反,从我的 shell 到 运行 多个实例如下:
# shell processes
$ for i in `seq 1 10`; do ./test_rand_fork.pl 1 & done
time: 1569511908.7708 - Random offset: 7.44 at pid: 4129
time: 1569511908.8070 - Random offset: 19.50 at pid: 4131
time: 1569511908.8068 - Random offset: 97.59 at pid: 4132
time: 1569511908.8073 - Random offset: 14.51 at pid: 4133
time: 1569511908.8077 - Random offset: 16.70 at pid: 4134
time: 1569511908.8080 - Random offset: 108.63 at pid: 4138
time: 1569511908.8079 - Random offset: 69.44 at pid: 4137
time: 1569511908.8080 - Random offset: 83.25 at pid: 4136
time: 1569511908.8080 - Random offset: 43.33 at pid: 4135
time: 1569511908.8203 - Random offset: 33.82 at pid: 4139
由于 "shell processes" 是一个丑陋的解决方案,我尝试使用 Math::Random::Secure。 这是我根据需要获得随机性的结果,但它比 "shell processes" 方法慢 50 倍:
# using: Math::Random::Secure qw(rand);
$ time ./test_rand_fork.pl 10
time: 1569510036.9331 - Random offset: 112.48 at pid: 2128
time: 1569510036.9470 - Random offset: 47.15 at pid: 2129
time: 1569510036.9501 - Random offset: 20.77 at pid: 2130
time: 1569510036.9517 - Random offset: 40.98 at pid: 2131
time: 1569510036.9521 - Random offset: 13.84 at pid: 2132
time: 1569510036.9538 - Random offset: 20.43 at pid: 2133
time: 1569510036.9543 - Random offset: 48.48 at pid: 2134
time: 1569510036.9563 - Random offset: 109.29 at pid: 2135
time: 1569510036.9579 - Random offset: 70.30 at pid: 2136
time: 1569510036.9601 - Random offset: 24.31 at pid: 2137
real 3m17.251s
user 32m31.129s
sys 0m1.054s
我需要的随机性不是为了安全起见,我只是需要一个好的传播。 有没有办法为分叉进程生成足够好的种子,并且仍然使用标准的 rand() 或更快的替代方法?或者至少不需要安装额外库的东西?
确实是srand你想要的。虽然确实通常不需要乱用它,但有一些用途
However, there are a few situations where programs are likely to want to call
srand
. One is for generating predictable results, generally for testing or debugging. There, you usesrand($seed)
, with the same$seed
each time.
而且,正是为了您的目的
Another case is that you may want to call
srand
after afork
to avoid child processes sharing the same seed value as the parent (and consequently each other).
一个简单的例子
perl -wE'
say "Parent $$ rand: ", rand;
for (1..4) {
$pid = fork // die "Cant fork: $!";
if ($pid == 0) { srand(); say "\tchild $$ rand: ", rand; exit }
}'
版画
Parent 23375 rand: 0.502774688721733
child 23376 rand: 0.914527430039929
child 23377 rand: 0.97985713889739
child 23378 rand: 0.127702740327553
child 23379 rand: 0.187181734786467
正是上面的 srand
起作用了;没有它,数字是相同的(因为它们必须是)。请注意,它也可以 运行 带有种子,这使我们可以更好地 diagnostic/testing 控制。
注意,避免传播坏习惯。
在上面的快速程序中,子进程被系统清理(由 init 回收)。然而,一个人真的应该总是收获所以上面真的应该
for (1..4) {
$pid = fork // die "Cant fork: $!";
if ($pid == 0) { srand(); say "\tchild $$ rand: ", rand; exit }
push @procs, $pid;
}
for (@procs) { $gone = wait; say "$gone exited with $?" }
waitpid and non-blocking for better monitoring, and perhaps in a signal handler 更好。