PHPCLI multi-process execution STARTUP script version 2

Source: Internet
Author: User
Not familiar with Linux Shell programming, I used PHP to write a multi-process parallel framework that can be run on a terminal. The function is very simple. It can basically handle some time-consuming tasks in batches in Linux (correct some errors in the first version and make some optimizations). Address: www. oschina. netcodesnippet_779765_000045 no #! Usr

Not familiar with Linux Shell programming, I used PHP to write a multi-process parallel framework that can be run on a terminal. Function is very simple, can basically meet the Linux at the same time batch processing some time-consuming work (correct some errors on the first version, and some optimization) Address of the first version: http://www.oschina.net/code/snippet_779765_44045 #! /Usr/

Not familiar with Linux Shell programming, I used PHP to write a multi-process parallel framework that can be run on a terminal. The function is very simple and can basically meet the needs of Linux to handle some time-consuming tasks in batch at the same time (correct some errors on the first version and make some optimizations)
Address of the first version: http://www.oschina.net/code/snippet_779765_44045 <无>
#! /Usr/bin/env php
  ** The bat-test.php script content is as follows:
  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, $ daemon = false, $ tasks = array (), $ msg, $ msgs = array (), $ logfile = "/tmp/bat. php. log ", $ childs, $ start, $ split, $ get, $ parent, $ wait; static function init () {set_time_limit (0); error_reporting (8106 & E_ALL ); ini_set ('display _ errors ', 'off'); set_error_handler (array (_ CLASS __, 'error'), E_ALL); set_exception_ha Ndler (array (_ CLASS __, 'exception'); register_shutdown_function (array (_ CLASS __, 'shutdown '); self: $ start = time (); self: $ split = str_repeat ('=', 512); self: $ parent = msg_get_queue (getmypid ();} static function main ($ inc) {self :: init (); ob_get_level () & ob_end_clean (); if ($ _ SERVER ["argc"] = 1) {if ($ inc) return true; self :: usage () ;}$ I = 0; $ daemon = false; $ files = array (); while (++ $ I <$ _ SERVER ["argc"]) {Switch ($ _ SERVER ["argv"] [$ I]) {case "? ": Case "/? ": Case "-? ": Case"-h ": case" -- help ": self: usage (); case"-f ": case" -- file ": if (++ $ I <$ _ SERVER ["argc"]) {$ file = $ _ SERVER ["argv"] [$ I]; if (is_readable ($ file) {$ files [] = $ file; continue;} self: message ("script $ file is not in or inaccessible", 2 ); self: end (4);} self: message ("script parameter missing", 1); echo "\ n please use $ _ ENV [_] -- help to view help! \ N "; self: end (1); case"-m ": case" -- max ": if (++ $ I <$ _ SERVER [" argc "]) {self: $ max = intval ($ _ SERVER ["argv"] [$ I]); if (self: $ max >=1) continue; self :: message ("Number of processes should be a positive integer", 2); self: end (8);} self: message ("Number of unspecified processes", 2); self :: end (7); case "-l": case "-- log": case "-- logfile": if (++ $ I <$ _ SERVER ["argc"]) {if (is_dir (self: $ logfile = $ _ SERVER ["argv"] [$ I]) {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); self: end (9);} self: message ("log file/directory missing", 2 ); self: end (6); case "-d": case "-- daemon": $ daemon = true; continue; case "-v": case "-- version ": self: $ daemon = true; exit (self: version (); default: $ file = $ _ SERVER ["argv"] [$ I]; if (is_readable ($ file) {$ files [] = $ file; continue;} else If ($ file [0] = '-') {self: message ("Unrecognized options $ file", 1);} else {self :: message ("the script $ file is not in or cannot be accessed", 2);} self: end (4) ;}}$ daemon & self: daemon (); foreach ($ files as $ file) {self: inc ($ file) ;}} 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) ;}} static function start () {self ::$ total + = count (self :: $ tasks); foreach (self: $ tas Ks as $ fun_arg) {if (self ::$ max <+ self ::$ running) {self: run_wait ($ cid);} elseif (self :: $ running = 1) {if (! Self: $ daemon) {# 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) ;}self: $ wait = 0;} if ($ cid = pcntl_fork () {if ($ cid <0) {throw new Exception ("failed to create process", 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_receive (self: $ get, 0, $ typ, 128, $ Msg); msg_send (self: $ parent, 1, getmypid (), false); call_user_func ($ fun_arg [0], $ fun_arg [1]); exit ;}} while (self ::$ running) self: run_wait ($ cid); self ::$ tasks = array ();} static function daemon () {if ($ cid = pcntl_fork () {if ($ cid <0) {throw new Exception ("process creation failed", 3);} self :: $ daemon = true; exit ("PID: $ cid \ n");} self: $ daemon = true;} static function is_da () {return self :: $ daemon;} static function set_max ($ max) {$ Max = intval ($ max); if ($ max> 0) self ::$ max = $ max;} static function set_logfile ($ log) {if (is_dir ($ log) {$ log. = "/bat. php. log ";} if (is_file ($ log) {if (is_writable ($ log) {self ::$ logfile = $ log ;}} else {if (is_writable (dirname ($ log) {self ::$ logfile = $ log ;}} static private function run_exit ($ cid, $ status) {if (! Pcntl_wifexited ($ status) | pcntl_wexitstatus ($ status) {$ msg = sprintf ("%-6d % s", $ cid, date ("H: I: s "), 'process exits abnormally '); if (pcntl_wifexited ($ status) {$ msg. = ', error code :'. pcntl_wexitstatus ($ status);} self: $ failure ++;} else {$ msg = sprintf ("%-6d % s", $ cid, date ("H: I: s"), 'process execution completed '); self ::$ finished ++;} unset (self ::$ childs [$ cid]); self: $ daemon | self: flush ($ msg, 4); self: $ running --;} static private function ru N_wait ($ cid) {static $ childs = array (); if (self ::$ wait) {if (self ::$ wait! = $ Cid) {# $ childs [$ cid] = time (); msg_send (self: $ childs [$ cid], 1, 'start ');}} else {foreach (self ::$ childs as $ cid =>$ t) {msg_send ($ t, 1, 'start '); # $ childs [$ cid] = time () ;}} self ::$ wait = $ cid; label_time: $ nomsg_interval = time () + 6; label_wait: $ time = time (); if (msg_receive (self: $ parent, 0, $ typ, 8192, $ msg, false, MSG_NOERROR | MSG_IPC_NOWAIT )) {if ($ typ = 3) {self: $ daemon | self: flush ($ msg, $ time);} e Lse {if ($ typ = 1) {$ msg = sprintf ("%-6d % s", $ msg, date ("H: I: s "), 'process start'); self: $ daemon | self: flush ($ msg, 3);} elseif ($ typ = 4) {if ($ cid = pcntl_waitpid ($ msg, $ status, WNOHANG) and $ cid> 0) {self: run_exit ($ cid, $ status); return ;}} elseif ($ typ = 5 & is_callable ("bat_diy_notify") {bat_diy_notify ($ msg) ;}} else {if (self: $ daemon) {if ($ cid = pcntl_wait ($ status, WNOHANG) and $ cid> 0) {self: run_exit ($ Cid, $ status); return;} else {sleep (6); goto label_time ;}} elseif (self: flush (null, 5 )) {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 (200000 );} if ($ nomsg_interval <$ time) {foreach (self ::$ childs as $ msg =>t t) {if ($ cid = pcntl_waitpid ($ msg, $ status, WNOHANG) and $ cid> 0) {self:: Run_exit ($ cid, $ status) ;}} if (self ::$ max> self ::$ running) return; goto label_time ;}goto label_wait ;} static function notify ($ msg, $ diy = false) {if ($ diy) {if (self ::$ get) {msg_send (self ::$ parent, 5, $ msg, false);} else {bat_diy_y y (string) $ msg) ;}} else {if (self ::$ daemon) {# msg_send (self ::$ parent, 5, self ::$ msg, false);} else {msg_send (self ::$ parent, 3, self ::$ msg. date ("H: I: s "). $ msg, false) ;}} static Function message ($ msg, $ code = 0) {if (self: $ daemon) {return true;} 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") {if (self: $ daemon) return true; # echo $ msg by default in the background, "(yes/no )?: "; # Return" yes \ n "= fgets (STDIN);} 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 ","-d | -- daemon starts background process execution and does not occupy terminal and output content \ n ", "Information: \ n", "$ bat: run (fun [, arg]) in the script to add task \ n", "fun is the name of the function to be executed; arg is the parameter passed to this function. It can save \ n "," \ n "," $ bat: start () called in the script () run the preceding task \ n "," in the child process, send the information to be displayed to the parent process \ n by calling $ bat: Running y (msg ", "In a sub-process, an error occurs in program execution. To make the main process statistics fail, exit (num) non-zero return \ n", "\ n ", "You can provide a bat_diy_notify (msg) function in the main process to record the data returned by the sub-process \ n", "the sub-process calls $ bat: notify (msg, true) to pass Send data to the parent process. The difference is that the true Parameter \ n is added. "NOTE: msg can only be a string and cannot be too long, to avoid unnecessary parts being discarded by the System \ n "; self: $ daemon = true; exit ();} static function version () {return" Version: 0.3 by huye \ n ";} static private function inc ($ file) {include $ file;} static private function end ($ code = 0) {if ($ code | self ::$ daemon) {# echo self ::$ total, "task completed \ n"; self ::$ daemon = true; exit ($ code) ;}$ cols = intval ('tput cols'); $ lines = intval ('tput lines'); if (self: $ Total) {self: flush ("execution completed. ", 2); echo" \ 33 [$ lines; {$ cols} H \ 33 [1C \ n ";} if (is_file (self: $ logfile) & filemtime (self ::$ logfile) >=self ::$ start) {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 execution completed: completed task", self ::$ finished, "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; $ _ max = $ 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 ;}} elseif ($ msg! = Null) {self ::$ msgs [] = $ msg;} static $ last_time = 0; if ($ last_time = $ time) return true; $ last_time = $ time; # prevent screen flushing during remote ssh. 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 (s Elf: $ msgs) + 4) >lines 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) {un Set ($ 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 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 (); self: $ daemon = true;} if (self: $ get) {msg_send (self: $ parent, 4, getmypid (), false ); # notify the parent process to end self ::$ parent = self ::$ get; # It also prevents the failure of the previous row of notification ob_end_clean () ;} else {self: end ();} msg_remove_queue (self: $ parent);} static function exception ($ e) {self: error ($ e-> getCode (), $ e-> getMessage (), $ e-> getFile (), $ e-> getLine (); exit ($ e-> getCode () ;}} bat: main (debug_backtrace ());
    
   
  

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.