Forking a running process and returning values

Standard

Using pcntl_fork() allows for forking of a running processing in PHP. In this example I fork my shell script and process data and return the results. This would be useful in a case where you had to make api calls to lets say 4 vendors: amazon, itunes, youtube, flickr. You would assign each child id a task to run. They each would then write there results to a shared memory location for further manipulation. I have written this test in CakePHP shell script.

class ForkShell extends AppShell {

    public function main() {

        $total = 0;
        $data = array();
        $result = array();
        $start = (float) array_sum(explode(' ', microtime()));

        echo "Parent PID: ".getmypid().PHP_EOL;

        $this->forkTest($data);

        // Manipulate the results from the fork
        foreach ($data as $key => $value) {
            $total = $total + $value['number'];
        }
        
        $result['sum_of_digits'] = $total;
        $result['data'] = $data;

        echo "Processing time: ".sprintf("%.4f", ((float) array_sum(explode(' ', microtime())) - $start))." seconds".PHP_EOL;
        print_r(Set::reverse($result));
    }

    public function forkTest(&$data = array()) {

        $pids = array();
        $parent_pid = getmypid();

        for ($i = 0; $i < 4; $i++) {
            if (getmypid() == $parent_pid) {
                $pids[] = pcntl_fork();
                echo "Forking child, now has ".count($pids)." elements".PHP_EOL;
            }
        }

        if (getmypid() == $parent_pid) {
	  		 
            // Process children results as they exit, but not before
            while (count($pids) > 0) {

                echo "Parent id: ".getmypid().PHP_EOL;

                // Wait for child to complete / maintains consistency
                $pid = pcntl_waitpid(-1, $status);
                // Open shared memory block (read only)
                $shm_id = shmop_open($pid, "a", 0, 0);
                // Read data based on chunk size to local variable
                $shm_data = unserialize(shmop_read($shm_id, 0, shmop_size($shm_id)));
                // Delete shared memory block
                shmop_delete($shm_id);
                // Close shared memory block
                shmop_close($shm_id);
                // Merge data to memory location of data
                $data = array_merge($data, $shm_data);
                /* Remove all PID entries created */
                foreach ($pids as $key => $tpid) {
                    if ($pid == $tpid) {
                        unset($pids[$key]);
                    }
                }
            }
            $pids = array();
            
        } else {

            echo "Child id: ".getmypid().PHP_EOL;

            // From here you could do API calls or other calculations and bring the results together
            $pdata = array();
            array_push($pdata, array(
                'child_id' => getmypid(),
                'number' => rand(5, 15)
            ));
            $data_str = serialize($pdata);

            // Open shared memory location
            $shm_id = shmop_open(getmypid(), "c", 0644, strlen($data_str));
            
            // attempt to write to shared memory
            if (!$shm_id) {
                exit("Couldn't create shared memory segment");
            } else if (shmop_write($shm_id, $data_str, 0) != strlen($data_str)) {
                exit("Couldn't write shared memory data");
            }

            exit(0);
        }
    }
}

I would not recommend running this script inside of CakePHP. It may cause issues with the caching.