- 演示图:
- 进程间通信使用unixsocket
- 完整参考代码:https://github.com/twomiao/Consumer
- 动态进程扩充原理代码,核心代码:
-
<?php $pidMap = []; $pidMapStatus = []; $forkTotal = 3; while ($forkTotal--) { $pid = pcntl_fork(); if ($pid > 0) { $pidMap[$pid] = $pid; $pidMapStatus[$pid] = 'idle'; } elseif ($pid == 0) { cli_set_process_title("child-worker"); $time = time(); while (1) { // 模拟:超过5秒钟向主进程汇报各自的状态,是否为忙碌还是空闲 if (time() - $time > 5) { $conn_socket = socket_create(AF_UNIX, SOCK_STREAM, 0); socket_connect($conn_socket, "./server.sock"); socket_write($conn_socket, serialize(['pid' => getmypid(), 'status' => 'busy'])); socket_recv($conn_socket, $recv_content, 2048, 0); socket_close($conn_socket); } // 模拟:超过30秒钟向主进程汇报各自的状态,是否为忙碌还是空闲 if (time() - $time > 30) { $conn_socket = socket_create(AF_UNIX, SOCK_STREAM, 0); socket_connect($conn_socket, "./server.sock"); socket_write($conn_socket, serialize(['pid' => getmypid(), 'status' => 'idle'])); socket_recv($conn_socket, $recv_content, 2048, 0); socket_close($conn_socket); $time = time(); } sleep(1); } exit(0); } else { $this->error('fork worker fail.'); } } cli_set_process_title("master-worker"); $mainSocket = socket_create(AF_UNIX, SOCK_STREAM, 0); $file = "./server.sock"; if (is_file($file)) { unlink($file); } socket_bind($mainSocket, $file); socket_listen($mainSocket); print_r($pidMapStatus); $time = time(); while (true) { $connection = socket_accept($mainSocket); socket_recv($connection, $buffer, 2048, 0); if ($buffer) { $data = unserialize($buffer); $pid = $data['pid']; $status = $data['status']; $pidMapStatus[$pid] = $status; // 全部worker 每隔5秒钟还是繁忙状态,我们就创建临时worker. if (time() - $time >= 5) { if (!in_array('idle', array_values($pidMapStatus), true)) { echo 'fork temp worker' . PHP_EOL; } else { // 存在空闲worker,此时说明不在繁忙.开始关闭临时worker echo 'exited temp worker' . PHP_EOL; } $time = time(); } } } while (count($pidMap)) { if ($pid = pcntl_wait($status, WUNTRACED) > 0) { print("exited worker pid:{$pid}, status:{$status}."); } }