【发布时间】:2020-01-26 22:59:20
【问题描述】:
我分叉了几个进程,我需要每个进程对随机选择的项目执行一项任务。 我发现分叉的进程选择了完全相同的随机数。 我尝试生成种子并调用 srand(),但没有太大帮助。实际上,我读过的大多数文档都建议避免使用 srand() “除非您确切知道自己在做什么”。
这是我的代码:
#!/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--;
}
当我运行它时,我会在每个进程中得到完全相同的“随机”数字:
$ 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 进程”是一个丑陋的解决方案,我尝试使用 Math::Random::Secure。 以下是我根据需要获得随机性的结果,但它比“shell 进程”方法慢 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() 或替代更快的方式?或者至少不需要安装额外的库?
【问题讨论】:
-
@PeterO。嗯,不——这讨论了一个不同的用例。当然,可以在
forks 中使用rand,这是srand的(极少数)目的之一(当相应地使用时)。在我的回答中查看示例
标签: perl random fork random-seed