PHP рд╕рдорд╛рдирд╛рдВрддрд░ рдХрд╛рд░реНрдпрдХреНрд░рдо
рдкрд╣рд▓реЗ, рд╡рд┐рд╖рдп рдХрд╛ рд╢реАрд░реНрд╖рдХ "рдмрд╣реБ-рдкрд┐рд░реЛрдпрд╛ PHP рдкреНрд░реЛрдЧреНрд░рд╛рдо рд▓рд┐рдЦрдирд╛" рдерд╛ ред PHP рдореЗрдВ рдХрдИ рдХреЛрд░ / рдкреНрд░реЛрд╕реЗрд╕рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ "рд╕рд╛рдорд╛рдиреНрдп" рддрд░реАрдХрд╛ рд╣реИ - рдпрд╣
рдХрд╛рдВрдЯрд╛ () рд╣реИ ред рдореИрдВ PHP рдФрд░ pcntl рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдореЗрдВ рдлреЛрд░реНрдХ () рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХреЗ рдЖрд╡реЗрджрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реВрдВрдЧрд╛ред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдо grep рдХрд╛ рдПрдХ рдХрд╛рдлреА рддреЗрдЬ рд╕рдорд╛рдирд╛рдВрддрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓рд┐рдЦреЗрдВрдЧреЗ (
find . -type f -print0 | xargs -0 -P $NUM_PROCS grep $EXPR
рд▓рд┐рдП рд╕рдорд╛рди рдЧрддрд┐ рдХреЗ рд╕рд╛рде
find . -type f -print0 | xargs -0 -P $NUM_PROCS grep $EXPR
)ред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
PHP рдореЗрдВ рдЗрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИ:
PHP_FUNCTION(pcntl_fork) { pid_t id; id = fork(); if (id == -1) { PCNTL_G(last_error) = errno; php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno); } RETURN_LONG((long) id); }
рдХрд╛рдВрдЯрд╛ () рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХреНрдпрд╛ рд╣реИ
рдХрд╛рдВрдЯрд╛ () рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ * рдирд┐рдХреНрд╕ рд╕рд┐рд╕реНрдЯрдо рдПрдХ рдРрд╕реА рдкреНрд░рдгрд╛рд▓реА рдХреЙрд▓ рд╣реИ рдЬреЛ рд╡рд░реНрддрдорд╛рди рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреА рдкреВрд░реА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдмрдирд╛рддреА рд╣реИред рдХрд╛рдВрдЯрд╛ () рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдЕрдкрдиреЗ рдореВрд▓реНрдп рдХреЛ рджреЛ рдЧреБрдирд╛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ: рдорд╛рддрд╛-рдкрд┐рддрд╛ рдХреЛ рдмрдЪреНрдЪреЗ рдХрд╛ рдкреАрдЖрдИрдбреА тАЛтАЛрдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рдмрдЪреНрдЪреЗ рдХреЛ 0. рдХрд╛рдлреА рдорд┐рд▓рддрд╛ рд╣реИ, рдХрдИ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рдпрд╣ рдХреЗрд╡рд▓ рдЙрди рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ рдЬреЛ рдХрдИ рд╕реАрдкреАрдпреВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред
$ php -r '$pid = pcntl_fork(); echo posix_getpid() . ": Fork returned $pid\n";' 9545: Fork returned 9546 9546: Fork returned 0
рдХрд╛рдВрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдиреБрдХрд╕рд╛рди ()
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдХрд╛рдВрдЯрд╛ () рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рд╕реНрдореГрддрд┐ рдореЗрдВ рдХреНрдпрд╛ рд╣реИ, рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪреЗ рдмрд┐рдирд╛ рд╣реА рд╡рд╣ рдЕрдкрдирд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ - рдпрд╣ рд╕рдм рдХреБрдЫ рдХреЙрдкреА рдХрд░рддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдРрд╕реЗ рдХрд╛рд░реНрдп рдЬреЛ рдПрдЯреИрдХреНрд╕рд┐рдЯ (рд░рдЬрд┐рд╕реНрдЯрд░_рд╢реВрдЯрдбрд╛рдЙрди_рдлрдВрдХреНрд╢рди) рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкрдВрдЬреАрдХреГрдд рд╣реИрдВред рдПрдХ рдЙрджрд╛рд╣рд░рдг:
$ php -r 'register_shutdown_function(function() { echo "Exited!\n"; }); pcntl_fork();' Exited! Exited!
рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдЕрдВрдд рдореЗрдВ, PHP рд╡рд┐рдирд╛рд╢рдХреЛрдВ (рдбреЗрдЯрд╛рдмреЗрд╕ рдХрдиреЗрдХреНрд╢рди рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЗ рдЖрдВрддрд░рд┐рдХ рд╡рд┐рдзреНрд╡рдВрд╕рдХ рд╕рд╣рд┐рдд) рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИред Mysqli рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреЗ рд▓рд┐рдП рдЙрджрд╛рд╣рд░рдг:
<?php $conn = new mysqli(..., "mysql") or die("Cannot connect\n"); $pid = pcntl_fork(); if ($pid > 0) { echo "Parent exiting\n"; exit(0); } echo "Sending query\n"; $res = $conn->query("SHOW TABLES") or die("Cannot get query result\n"); print_r($res->fetch_all());
рдХрд╛рд░реНрдпрдХреНрд░рдо рдХрд╛ рдЖрдЙрдЯрдкреБрдЯ рдЖрд╡рд╢реНрдпрдХ рд░реВрдк рд╕реЗ рд▓рд┐рдЦрд┐рдд рдирд╣реАрдВ рд╣реЛрдЧрд╛ред рдХрднреА-рдХрднреА рдорд╛рддрд╛-рдкрд┐рддрд╛ рдореЗрдВ рдХрдиреЗрдХреНрд╢рди рдХреЛ рдмрдВрдж рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╕реЗ рдкрд╣рд▓реЗ рдмрдЪреНрдЪреЗ рдХреЗ рдкрд╛рд╕ "рд╕рдордп" рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдЙрд╕реЗ рд╕рдм рдХреБрдЫ рдЙрд╕реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИ рдЬреИрд╕реЗ рдЙрд╕реЗ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдХрд╛рд░реНрдпреЛрдВ / рд╡рд┐рдзреНрд╡рдВрд╕рдХ рдХреЗ рдЖрд╕реНрдердЧрд┐рдд рдирд┐рд╖реНрдкрд╛рджрди рд╕реЗ рдирд┐рдкрдЯрдирд╛
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╕реНрдердЧрд┐рдд рдирд┐рд╖реНрдкрд╛рджрди рдХреА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдпрджрд┐ рдЖрдк рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЖрдк рдХреНрдпрд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, C рдореЗрдВ рдПрдХ рдлрд╝рдВрдХреНрд╢рди
_exit () рд╣реИ , рдЬреЛ рдХрд┐рд╕реА рднреА рд╕реНрдерд╛рдкрд┐рдд рд╣реИрдВрдбрд▓рд░ рдХреЛ рд╢реБрд░реВ рдХрд┐рдП рдмрд┐рдирд╛ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рддрд╛ рд╣реИред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, PHP рдореЗрдВ рдРрд╕рд╛ рдХреЛрдИ рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдВрдХреЗрддреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕рдХрд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рдЖрдВрд╢рд┐рдХ рд░реВрдк рд╕реЗ рдЕрдиреБрдХрд░рдг рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
function _exit() { posix_kill(posix_getpid(), SIGTERM); }
рдпрд╣ "рд╣реИрдХ" рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рджреЛ PHP рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдХрдиреЗрдХреНрд╢рди рдХреЛ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реЛрдЧрд╛, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рдмреЗрд╣рддрд░ рд╣реИ, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдирд╣реАрдВ :):
<?php $conn = new mysqli(..., "mysql") or die("Cannot connect\n"); function _exit() { posix_kill(posix_getpid(), SIGTERM); } function show_tables() { global $conn; echo "Sending query\n"; $res = $conn->query("SHOW TABLES") or die("Cannot get query result\n"); echo "Tables count: " . $res->num_rows . "\n"; } $pid = pcntl_fork(); if ($pid > 0) { show_tables(); _exit(); } sleep(1); show_tables();
рдЧреНрд░рд┐рдк рд▓рд┐рдЦрдирд╛
рдЕрдм, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, grep рдХрд╛ рдПрдХ рд╕рд░рд▓ рд╕рдВрд╕реНрдХрд░рдг рд▓рд┐рдЦреЗрдВ, рдЬреЛ рд╡рд░реНрддрдорд╛рди рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рдорд╛рд╕реНрдХ рджреНрд╡рд╛рд░рд╛ рдЦреЛрдЬ рдХрд░реЗрдЧрд╛ред
<?php exec("find . -type f", $files, $retval);
Grep рдХрд╛ рдПрдХ рд╕рдорд╛рдирд╛рдВрддрд░ рд╕рдВрд╕реНрдХрд░рдг рд▓рд┐рдЦрдирд╛
рдЕрдм рдЖрдЗрдП рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪреЗрдВ рдХрд┐ рдЖрдк рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рдХреИрд╕реЗ рд╕рдорд╛рдирд╛рдВрддрд░ рдХрд░рдХреЗ рдЗрд╕реЗ рдЧрддрд┐ рджреЗ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдк рдЖрд╕рд╛рдиреА рд╕реЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдо $ рдлрд╛рдЗрд▓реНрд╕ рдРрд░реЗ (рдлрд╛рдЗрд▓ рд▓рд┐рд╕реНрдЯ) рдХреЛ рдХрдИ рд╣рд┐рд╕реНрд╕реЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрди рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЛ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдФрд░ рд╣рдо рдЗрд╕реЗ рд╕рднреА рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХрд╛рд░реНрдпреЛрдВ рдХреА рдПрдХ рдмрдбрд╝реА рд╕реВрдЪреА рд╣реЛрддреА рд╣реИ: рд╣рдо рдкреНрд░рддреНрдпреЗрдХ Nth рдХреЛ рдЗрд╕реА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдЗрд╕рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдпрд╛ рдХрдо рд╕рд╛рдорд╛рдиреНрдп рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦреЗрдВрдЧреЗ:
define('PROCESSES_NUM', 2);
рдпрд╣ рд╣рдорд╛рд░реЗ рд╕рдорд╛рдирд╛рдВрддрд░рдлреЙрд░рдЪ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рд╕рд╛рде рдлрд╝реЙрд░рдЪ () рдХреЛ рдмрджрд▓рдиреЗ рдФрд░ рддреНрд░реБрдЯрд┐ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛ рд╣реБрдЖ рд╣реИ:
рдкреВрд░реНрдг рд╕реНрд░реЛрдд <?php define('PROCESSES_NUM', 2); if ($argc != 2) { fwrite(STDERR, "Usage: $argv[0] <pattern>\n"); exit(1); } grep($argv[1]); function grep($pattern) { exec("find . -type f", $files, $retval); if ($retval) exit($retval); $pattern = "/$pattern/m"; if (false === preg_match($pattern, '123')) { fwrite(STDERR, "Incorrect regular expression\n"); exit(1); } parallelForeach($files, function($f) use ($pattern) { grepFile($pattern, $f); }); exit(0); } function grepFile($pattern, $file) { $fp = fopen($file, "rb"); if (!$fp) { fwrite(STDERR, "Cannot read $file\n"); return; } $binary = strpos(fread($fp, 1024), "\0") !== false; fseek($fp, 0); if ($binary) { if (preg_match($pattern, file_get_contents($file))) echo "$file: binary matches\n"; } else { while (false !== ($ln = fgets($fp))) { if (preg_match($pattern, $ln)) echo "$file:$ln"; } } fclose($fp); } function parallelForeach($arr, $func) { for ($proc_num = 0; $proc_num < PROCESSES_NUM; $proc_num++) { $pid = pcntl_fork(); if ($pid < 0) { fwrite(STDERR, "Cannot fork\n"); exit(1); } if ($pid == 0) break; } if ($pid) { for ($i = 0; $i < PROCESSES_NUM; $i++) { pcntl_wait($status); $exitcode = pcntl_wexitstatus($status); if ($exitcode) exit(1); } return; } $l = count($arr); for ($i = $proc_num; $i < $l; $i += PROCESSES_NUM) $func($arr[$i]); exit(0); }
PHP 5.3.10 рдХреЗ рд╕реЛрд░реНрд╕ рдХреЛрдб рдкрд░ рд╣рдорд╛рд░реЗ grep рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ:
$ php ~/parallel-grep.php '^PHP_FUNCTION' | head ./ext/calendar/calendar.c:PHP_FUNCTION(cal_info) ./ext/calendar/calendar.c:PHP_FUNCTION(cal_days_in_month) ./ext/calendar/calendar.c:PHP_FUNCTION(cal_to_jd) ./ext/calendar/calendar.c:PHP_FUNCTION(cal_from_jd) ./ext/calendar/calendar.c:PHP_FUNCTION(jdtogregorian) ./ext/calendar/calendar.c:PHP_FUNCTION(gregoriantojd) ./ext/calendar/calendar.c:PHP_FUNCTION(jdtojulian) ./ext/calendar/calendar.c:PHP_FUNCTION(juliantojd) ./ext/calendar/calendar.c:PHP_FUNCTION(jdtojewish) ./ext/calendar/calendar.c:PHP_FUNCTION(jewishtojd) $ time php ~/parallel-grep.php '^PHP_FUNCTION' | wc -l 4056 real 0m2.073s user 0m3.265s sys 0m0.550s $ time grep -R '^PHP_FUNCTION' . | wc -l 4056 real 0m3.646s user 0m3.415s sys 0m0.209s $ time find . -type f -print0 | xargs -0 -P 2 grep '^PHP_FUNCTION' | wc -l 4056 real 0m1.895s user 0m3.247s sys 0m0.249s
рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ! рдореИрдВрдиреЗ PHP рдореЗрдВ рд╕рдорд╛рдирд╛рдВрддрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдореЗрдВ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдкреИрдЯрд░реНрди рдореЗрдВ рд╕реЗ рдПрдХ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рд╣реИ - рдХрд╛рд░реНрдпреЛрдВ рд╕реЗ рдПрдХ рдХрддрд╛рд░ рдХреЗ рд╕рдорд╛рдирд╛рдВрддрд░ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдгред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдореЗрд░рд╛ рд▓реЗрдЦ рдХрд┐рд╕реА рдХреЛ рдмрд╣реБ-рдереНрд░реЗрдбреЗрдб PHP рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рд▓рд┐рдЦрдиреЗ рд╕реЗ рдбрд░рдиреЗ рд╕реЗ рд░реЛрдХрдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ рдпрджрд┐ рдХрд╛рд░реНрдп рдЗрд╕ рддрд░рд╣ рдХреЗ рдЕрдкрдШрдЯрди рдХреЗ рд░реВрдк рдореЗрдВ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЖрдкрдХрд╛ рдзрдиреНрдпрд╡рд╛рдж