在分叉的子代上调用rand/mt_rand会产生相同的结果

gal*_*hen 3 php random fork

我正在编写一个需要在PHP中执行并发任务的脚本.

我跑了一点测试,遇到了奇怪的结果.我正在使用pcntl_fork生成一个孩子.父进程只会等待孩子完成.

我正在生成5个孩子,每个孩子都运行一个函数,生成一个随机数(秒)并且睡了那么长时间.出于某种原因 - 所有孩子都生成相同的数字.

这是一个代码示例:

private $_child_count = 0;

private function _fork_and_exec($func)
{
    $cid = ++$this->_child_count;
    $pid = pcntl_fork();
    if ($pid){  // parent
        return $pid;
    } else {    // child
        $func($cid);
        //pcntl_waitpid(-1, $status);
        exit;
    }
}
public function parallel_test()
{
    $func = function($id){
        echo 'child ' . $id . ' starts'."\n";
        $wait_time = mt_rand(1,4);
        echo 'sleeping for '.$wait_time."\n";
        sleep($wait_time);
        echo 'child ' . $id . ' ends'."\n";
    };
    $children = [];
    for ($i=0; $i<5; $i++){
        $children[] = $this->_fork_and_exec($func) ."\n";
    }
    pcntl_wait($status);
    echo 'done' ."\n";
    exit;
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

child 1 starts
sleeping for 1
child 2 starts
sleeping for 1
child 3 starts
sleeping for 1
child 4 starts
sleeping for 1
child 5 starts
sleeping for 1
child 1 ends
child 2 ends
child 3 ends
child 4 ends
child 5 ends
done
Run Code Online (Sandbox Code Playgroud)

提前致谢

JvO*_*JvO 5

这是因为所有子节点都以相同的状态开始(fork()复制代码和数据段).由于rand和mt_rand是伪随机生成器,它们都将生成相同的序列.

您将不得不重新初始化随机生成器,例如使用进程/线程ID或从/ dev/urandom读取几个字节.

  • 要在这个答案的基础上稍微构建一下,请使用诸如“mt_srand”之类的内容和线程 ID 来重新播种随机数生成器 (2认同)