PHPCLI multi-process execution startup script 1.
2. bat. php
#! /Usr/bin/env php
159);} function B ($ line) {do {bat: Y ("I am passing the parameter \ $ line = $ line"); usleep (500000 );} while (mt_rand (100,999)> 359);} function c () {global $ x; bat: notify ("The initial variable values between multiple tasks are not affected, \ $ x = $ x "); bat: notify (" I'm suspending the 9-second test "); sleep (9); bat :: Y ("I'm an error code 5 test"); exit (5);} *?> * // ** Make sure that this script can only run in SHELL */if (substr (php_sapi_name (), 0, 3 )! = 'Cli ') {die ("This Programe can only be run in cli mode. \ n");} if (! Is_callable ('pcntl _ fork') |! Is_callable ('MSG _ send') {bat: message ("this program requires pcntl, sysvmsg extension, but your system is not installed! ", 2); exit (5);} class bat {static private $ max = 3, $ total = 0, $ running = 0, $ failure = 0, $ finished = 0, $ tasks = array (), $ msg, $ msgs = array (), $ logfile = "/tmp/bat. php. log ", $ childs, $ get, $ parent, $ start, $ split; static function main () {$ I = 1; $ files = array (); if ($ _ SERVER ["argc"]> 1) {while ($ I <$ _ SERVER ["argc"]) {switch ($ _ SERVER ["argv"] [$ I ++]) {case "? ": Case "/? ": Case "-? ": Case"-h ": case" -- help ": self: usage (); case"-f ": case" -- file ": $ file = $ _ SERVER ["argv"] [$ I ++]; if (is_readable ($ file) {$ files [] = $ file; continue ;} if (is_null ($ file) {self: message ("script parameter missing", 1); help (1) ;}else {self :: message ("script $ file is not in or inaccessible", 2); exit (4);} case "-m": case "-- max": if (self :: $ max = $ _ SERVER ["argv"] [$ I ++]) {self ::$ max = intval (self ::$ max); if (self :: $ max> = 1) {continue ;} Self: message ("number of processes should be a positive integer", 2); exit (8) ;}self: message ("number of unspecified processes", 2 ); exit (7); case "-l": case "-- log": case "-- logfile": if (self :: $ logfile = $ _ SERVER ["argv"] [$ I ++]) {if (is_dir (self ::$ logfile) {self ::$ logfile. = "/bat. php. log ";} if (is_file (self ::$ logfile) {if (is_writable (self ::$ logfile) {continue ;}} else {if (is_writable (dirname (self: $ logfile) {continue;} self: message ("log directory cannot be written", 2); e Xit (9);} case "-v": case "-- version": exit (self: version (); default: $ file = $ _ SERVER ["argv"] [$ I-1]; if (is_readable ($ file) {$ files [] = $ file; continue;} self:: message ("The script $ file is not in or cannot be accessed", 2); exit (4) ;}} set_time_limit (0); error_reporting (8106 & E_ALL ); ini_set ('display _ errors ', 'off'); set_error_handler (array (_ CLASS __, 'error'), E_ALL); set_exception_handler (array (_ CLASS __, 'exception ') ); Register_shutdown_function (array (_ CLASS __, 'shutdown '); self: $ start = time (); self: $ split = str_repeat (' = ', 512); self ::$ parent = msg_get_queue (getmypid (); foreach ($ files as $ file) {self: inc ($ file);} self :: end (); exit;} self: usage ();} static function run ($ fun, $ arg = null) {if (is_callable ($ fun) {self :: $ tasks [] = array ($ fun, $ arg);} else {throw new Exception ("not a function or cannot be called", 9);} stati C function start () {self ::$ total = count (self ::$ tasks); foreach (self ::$ tasks as $ fun_arg) {if (self :: $ max <++ self ::$ running) {self: run_wait ();} elseif (self: $ running = 1) {# clear the screen and set the cursor to the first line $ x = intval ('tput Lines'); echo str_repeat ("\ n", $ x-1); self :: flush ('Program starts to execute... ', 1) ;}if ($ cid = pcntl_fork () {if ($ cid <0) {throw new Exception ("process creation failed", 3);} self:: $ childs [$ cid] = msg_get_queue ($ cid);} else {Ob_start (); self ::$ tasks = array (); self ::$ get = msg_get_queue (getmypid (); self :: $ msg = sprintf ("%-6d", getmypid (); msg_send (self: $ parent, 1, getmypid (), false ); call_user_func ($ fun_arg [0], $ fun_arg [1]); exit ;}} while (self ::$ running) self: run_wait (); self :: $ tasks = array ();} static private function run_wait () {$ nomsg_interval = time (); label_wait: if (msg_receive (self: $ parent, 0, $ typ, 8192, $ Msg, false, MSG_NOERROR | MSG_IPC_NOWAIT) {if ($ typ! = 3) {if ($ typ = 1) {$ msg = sprintf ("%-6d % s", $ msg, date ("H: I: s "), 'process start');} elseif ($ typ = 4) {label_child_exit: unset (self ::$ childs [pcntl_waitpid ($ msg, & $ status)]); if (! Pcntl_wifexited ($ status) | pcntl_wexitstatus ($ status) {$ msg = sprintf ("%-6d % s", $ msg, date ("H: I: s "), 'process exits abnormally '); if (pcntl_wifexited ($ status) {$ msg. = ', error code :'. pcntl_wexitstatus ($ status);} self: $ failure ++;} else {$ msg = sprintf ("%-6d % s", $ msg, date ("H: I: s"), 'process execution completed '); self: $ finished ++;} self: flush ($ msg, $ nomsg_interval ); self: $ running --; return;} else {goto label_wait; }}$ nomsg_in Terval = time (); self: flush ($ msg, $ nomsg_interval);} else {if ($ nomsg_interval! = Time () {foreach (self: $ childs as $ msg => $ t) {if (! Msg_queue_exists ($ msg) {goto label_child_exit;} echo "\ 33 [0; 0 H"; $ lines = intval ('tput Lines '); echo "\ 33 [K running duration:", self: run_time (), '', date (" Y-m-d H: I: s ", self :: $ start), '-', date ("Y-m-d H: I: s"), "\ 33 [$ lines; 0 H ";} usleep (100000);} goto label_wait;} static function running y ($ msg) {msg_send (self ::$ parent, 3, self ::$ msg. date ("H: I: s "). $ msg, false);} static function message ($ msg, $ code = 0) {switch ($ code) {case 0: echo "\ 33 [37m prompt: \ 33 [0 m", $ msg, "\ n"; break; case 1: echo "\ 33 [33m warning: \ 33 [0 m", $ msg, "\ n"; break; case 2: echo "\ 33 [31m error: \ 33 [0 m ", $ msg," \ n "; break ;}} static function confirm ($ msg =" OK to continue executing ") {echo $ msg, "(yes/no )?: "; # Return" yes \ n "= fgets (STDIN);} static function help ($ code = 0) {echo "\ n please use $ _ ENV [_] -- help to view help! \ N "; $ code & exit ($ code);} static function usage () {$ bat = _ CLASS __; echo" "," Usage: \ n ", "$ _ ENV [_] [options] [-f | -- file]
\ N "," Options: \ n ","-h | -- help: Display the help information \ n ","-v | -- version: view the program version \ n ", "\ n", "-m | -- max
Number of processes simultaneously executed. default value: ", self: $ max," \ n ","-l | -- log
Error log file. default value: ", self: $ logfile," \ n "," Information: \ n "," $ bat: run (fun [, arg]) to add task \ n "," fun is the name of the function to be executed; arg is the parameter passed to this function, which can save \ n "," \ n ", "The script calls $ bat: start () to start the process to execute the added task \ n", "in the sub-process, by calling $ bat: running y (msg) send the information to be displayed to the parent process \ n "," in the child process, an error occurs in program execution. to make the main process count as failed, exit (num) is required) non-zero return \ n "; exit;} static function version () {return" Version: 0.1 by huye \ n ";} static private function inc ($ file) {include $ File;} static private function end () {$ cols = intval ('tput cols'); $ lines = intval ('tput Lines'); if (self: $ total) {self: flush ("execution completed. ", 1); echo" \ 33 [$ lines; {$ cols} H \ 33 [1C \ n ";} if (is_file (self: $ logfile )) echo "\ 33 [K error:", self: $ logfile, "\ n"; echo "\ 33 [K running duration:", self :: run_time (), '', date (" Y-m-d H: I: s ", self: $ start ),'-', date ("Y-m-d H: I: s"), "\ n"; echo "\ 33 [K completed: completed task", self: $ finishe D, "count", self: $ failure? ", Failed". self: $ failure. ":" ", self: $ total? "(Total". self: $ total )":"",". \ N ";} static private function flush ($ msg, $ time) {$ cols = intval ('tput cols'); $ lines = intval ('tput Lines '); if ($ msg) {$ _ max = $ cols; foreach (explode ("\ n", $ msg) as $ msg) {if ($ cols <strlen ($ msg) {# ascii utf8 ascii utf8 ascii... $ tmp = preg_split ("#((?: [\ Xe0-\ xef] [\ x80-\ xbf] {2}) +) # ", $ msg, 0, PREG_SPLIT_DELIM_CAPTURE); for ($ I = 0, $ l = count ($ tmp); $ I <$ l;) {$ x = strlen ($ z = $ tmp [$ I]); if ($ _ max >$ x) {_ _ max-= $ x; if (++ $ I >=$ l) break; $ x = strlen ($ z = $ tmp [$ I])/3*2; if ($ _ max> $ x) {$ _ max-= $ x; $ I ++; continue;} elseif ($ _ max <$ x) {$ _ max = floor ($ _ max/2) * 3; $ msg = array_slice ($ tmp, $ I-1); $ msg [0] = ''; $ msg [1] = substr ($ z, $ _ max ); $ tmp [$ I] = substr ($ z, 0, $ _ max);} else {$ msg = array_slice ($ tmp, $ I + 1 );}} elseif ($ _ max <$ x) {$ msg = array_slice ($ tmp, $ I); $ msg [0] = substr ($ z, $ _ max ); $ tmp [$ I] = substr ($ z, 0, $ _ max);} else {$ msg = array_slice ($ tmp, $ I ); $ msg [0] = '';} if (++ $ I <$ l) {array_splice ($ tmp, $ I );} if (isset ($ msg [1]) {self: $ msgs [] = implode ("", $ tmp); $ msg [0] = "". $ msg [0]; $ I = 0; $ l = count ($ msg); $ tmp = $ msg; $ _ m Ax = $ cols;} elseif (isset ($ msg [0]) & strlen ($ msg [0]) {self :: $ msgs [] = implode ("", $ tmp); if ($ cols-15 <strlen ($ msg [0]) {foreach (str_split ($ msg [0], $ cols-15) as $ tmp) {$ tmp = "". $ tmp; if ($ cols = strlen ($ tmp) {self ::$ msgs [] = $ tmp;} else {$ tmp = array ($ tmp ); break ;}} else {$ tmp = array ("". $ msg [0]);} break;} else {break;} self: $ msgs [] = implode ("", $ tmp);} else {self :: $ msgs [] = $ Msg ;}} else {self: $ msgs [] = $ msg;} static $ last_time = 0; if ($ last_time = $ time) return true; $ last_time = $ time; # prevent screen flushing when remote ssh occurs echo "\ 33 [0; 0 H"; # echo "\ 33 [K program information:", self:: version (); echo "\ 33 [K running duration:", self: run_time (), '', date (" Y-m-d H: I: s ", self: $ start), '-', date (" Y-m-d H: I: s ")," \ n "; if ($ lines <5) {if ($ lines <3) return;} else {echo $ split = substr (self: $ split, 0, $ cols ),"\ N "; if ($ _ max = count (self: $ msgs) + 4)> $ lines) {array_splice (self: $ msgs, 0, $ _ max-$ lines);} elseif ($ lines >$ _ max) {$ split = str_repeat ("\ n \ 33 [K ", $ lines-$ _ max ). $ split;} echo "\ 33 [K", implode ("\ n \ 33 [K", self: $ msgs), "\ n", $ split, "\ n" ;}$ msg = "completed task ". self: $ finished. "; if (self: $ failure) $ msg. = ", failed ". self: $ failure. "; if (self: $ total) $ msg. = "(total ". self: $ total.") "; Echo str_repeat ('', $ cols-strlen (preg_replace ("# [\ xe0-\ xef] [\ x80-\ xbf] {2 }#", "**", $ msg), $ msg, "\ 33 [$ lines; 0 H";} static function run_time () {$ consume = time () -self: $ start; $ str = ""; if ($ consume >=86400) {$ str = floor ($ consume/86400 ). "Day"; $ consume = $ consume % 86400; $ zero = true;} if ($ consume >=3600) {$ str. = floor ($ consume/3600 ). "hour"; $ consume = $ consume % 3600; $ zero = True;} elseif ($ consume> 0 & isset ($ zero) {unset ($ zero); $ str. = "zero";} if ($ consume >=60) {$ str. = floor ($ consume/60 ). "points"; $ consume = $ consume % 60; $ zero = true;} elseif ($ consume> 0 & isset ($ zero) {unset ($ zero ); $ str. = "0";} if ($ consume> 0) {$ str. = $ consume. "Seconds";} elseif ($ str = "") {$ str = "0 seconds";} return $ str;} static function error ($ no, $ err, $ file, $ line) {if (error_reporting ()) {$ Log = $ no & 1032? & Apos; M & apos;: ($ no & 514? 'W': ($ no & 2048? 'M': 'e'); $ log = "[". date ("m-d H: I: s "). "] $ log $ line $ file $ err \ n"; file_put_contents (self ::$ logfile, $ log, FILE_APPEND) ;}} static function shutdown () {if ($ last = error_get_last () and 85 & $ last ['type']) {self: error ($ last ['type'], $ last ['message'], $ last ['file'], $ last ['line']); self ::$ get | self: end ();} if (self ::$ get) {msg_send (self ::$ parent, 4, getmypid (), false); # notifies the parent process to end self ::$ parent = self :: $ get; # it also prevents the failure of the previous row of notification ob_end_clean ();} msg_remove_queue (self ::$ parent);} static function exception ($ e) {self :: error ($ e-> getCode (), $ e-> getMessage (), $ e-> getFile (), $ e-> getLine ()); exit ($ e-> getCode () ;}} bat: main ();