rikanishu/php-multi-process

用于并行执行shell命令的PHP库

0.2.4 2016-09-13 16:26 UTC

This package is not auto-updated.

Last update: 2024-09-28 15:00:40 UTC


README

用于并行执行shell命令的PHP库 构建状态

通过composer安装

运行以下命令之一

php composer.phar require rikanishu/php-multi-process "*"

或在你的 composer.json 文件的 require 部分添加

"rikanishu/php-multi-process": "*"

以下内容。

示例

$cmd1 = ['echo', '"Some Command"'];
$cmd2 = 'echo "Another Command"';
$cmd3 = ['echo "$SOME_ENV_VAR" "$PWD"', [
    rikanishu\multiprocess\Command::OPTION_CWD => '/tmp',
    rikanishu\multiprocess\Command::OPTION_ENV =>  [
        'SOME_ENV_VAR' => 'PWD is:'
    ],
]];
$cmd4 = new rikanishu\multiprocess\Command('cat');
$cmd4->setStdin('hello world');

$pool = new rikanishu\multiprocess\Pool([$cmd1, $cmd2, $cmd3, $cmd4]);
$pool->run();

/* @var $command rikanishu\multiprocess\Command */
foreach ($pool->getCommands() as $command) {
    $res = $command->getExecutionResult();
    echo $res->getExitCode() . " | " . $res->getStdout() . " | " . $res->getStderr() . "\n";
}

/*  Output:
    0 | Some Command |
    0 | Another Command |
    0 | PWD is: /tmp |
*/

$commands = $pool->getCommands();
$commands[0]->getExecutionResult()->getOutput(); // Some Command
$commands[1]->getExecutionResult()->getOutput(); // Another Command
$commands[2]->getExecutionResult()->getOutput(); // PWD is: /tmp
$commands

/* And also library provides single command execution */
$command = new rikanishu\multiprocess\Command('echo "Hello World!"');
$command->runBlocking()->getOutput(); // Hello World

描述

此库旨在在阻塞/非阻塞模式下执行单个/多个并行进程。该库提供了一种方便的配置外部进程执行的方法。基本概念是Pool和Command对象。Pool是一组创建并委托执行给ExecutionContext的命令。ExecutionContext为每个命令构建Process对象并运行它。Command对象代表单个外部命令。

该库使用由标准PHP库提供的proc_* API和select系统调用。它没有外部依赖。

使用方法

一般的用法场景表明,你可以将一些命令传递给一个Pool实例,该实例将在阻塞/非阻塞模式下并行执行,具体取决于传递的参数。以下是非阻塞执行四个命令的示例

$cmd1 = ['echo', '"Some Command"'];
$cmd2 = 'echo "Another Command"';
$cmd3 = ['echo "$SOME_ENV_VAR" "$PWD"', [
    rikanishu\multiprocess\Command::OPTION_CWD => '/tmp',
    rikanishu\multiprocess\Command::OPTION_ENV =>  [
        'SOME_ENV_VAR' => 'PWD is:'
    ],
]];
$cmd4 = new rikanishu\multiprocess\Command('cat');
$cmd4->setStdin('hello world');

$pool = new rikanishu\multiprocess\Pool([$cmd1, $cmd2, $cmd3, $cmd4]);
$pool->run();

/* @var $command rikanishu\multiprocess\Command */
foreach ($pool->getCommands() as $command) {
    $res = $command->getExecutionResult();
    echo $res->getExitCode() . " | " . $res->getStdout() . " | " . $res->getStderr() . "\n";
}

$cmd1$cmd2$cmd3$cmd4 显示了Pool应用的命令的不同格式。你也可以直接传递Command实例,因为Pool隐式地将shell命令文本转换为Command实例,并首先检查此类输入数据。

$cmd5 = new rikanishu\multiprocess\Command(‘echo instance’);
…

$pool = new rikanishu\multiprocess\Pool([$cmd1, $cmd2, $cmd3, $cmd4, $cmd5]);
$pool->run();

Pool的run()方法返回代表每个命令的Futures数组,例如上面的示例中的$future[3]代表$cmd4。你可以始终使用$command->getFuture()方法来获取正在执行的命令的当前future。未执行的命令没有future,如果你为未执行的Command调用getFuture(),将会抛出异常。你可以调用hasFuture()来检查你的代码不知道,命令是否已经运行或尚未运行。

$cmd1 = ['echo', '"Some Command"'];
$cmd2 = 'echo "Another Command"';
$cmd3 = new rikanishu\multiprocess\Command(‘echo instance’);

$pool = new rikanishu\multiprocess\Pool([$cmd1, $cmd2, $cmd3]);
$futures = $pool->run();
$commands = $pool->getCommands();

print_r(count($commands)); // Count of command objects always equals passed shell commands. Pool raise an exception on creation step if command has invalid format.
print_r($cmd3 == $commands[2]); // Equals
print_r($commands[1]->hasFuture()); // True, command is running
print_r($commands[1]->getFuture() == $futures[1]); // Equals
print_r($commands[1]->getFuture()->getResult()); // Block and waiting execution result
//Or you can block process directly by alias command method
print_r($command[1]->getExecutionResult()); // Alias of Future’s getResult()

在非阻塞模式下,$pool->run()调用创建一个进程数组并返回控制权给调用程序。进程将在后台同时执行,当你调用Future的getResult()方法时,它将阻塞执行过程直到收到结果或时间限制到期。如果你想避免阻塞并继续你的有用计算过程,你可以始终检查Future的hasResult()

$pool = new rikanishu\multiprocess\Pool([$cmd1, $cmd2, $cmd3]);
$futures = $pool->run();
…
//doing some useful work
…
if ($furures[1]->hasResult()) {
…
}
//doing another useful work
…
//block and waiting data finally
$result = $futures[1]->getResult();

此外,如果你只需要运行单个命令,可以直接使用命令方法的run()。它将创建一个新的包含单个命令的Pool并返回Future。使用方法runBlocking()以阻塞模式运行执行并接收执行结果。

$command = new rikanishu\multiprocess\Command('echo "Hello World!"');
$command->runBlocking()->getOutput(); // Hello World

或者

$command = new rikanishu\multiprocess\Command('echo "Hello World!"');
$future = $command->run();
…
// doing some useful work
…
$future->getResult()->getOutput(); // Hello World

Pool选项

Pool接受一个选项数组作为第二个参数。你可以通过两种方式设置Pool的选项

  • 将选项数组作为Pool构造函数的第二个参数传递
$pool = new rikanishu\multiprocess\Pool([$cmd1, $cmd2, $cmd3], [
	rikanishu\multiprocess\Pool::OPTION_EXECUTION_TIMEOUT => 120,
	rikanishu\multiprocess\Pool::OPTION_BLOCKING_MODE => true
]);
  • 在创建对象后设置参数
$pool->setExecutionTimeout(120);
$pool->setBlockingMode(true);
选项列表
  • OPTION_EXECUTION_TIMEOUT - 执行过程的秒数限制。小于零的值表示无限制的超时。默认为-1(无限制)。选项的别名方法是$pool->setExecutionTimeout(200)

  • OPTION_POLL_TIMEOUT - 每个选择轮询周期的最大超时时间(秒)。这意味着等待运行中的进程的任何反应的时间,如果没有任何反应(例如,输出到stdout / stderr或停止执行),则在读取进程状态后重试轮询周期。默认值为60秒。此选项的别名方法是 $pool->setPollTimeout(120)

  • OPTION_SELECT_USLEEP_TIME - 如果select调用返回false或系统不支持进程轮询(例如在Windows上),则轮询周期的微秒数。默认为200微秒。此选项的别名方法是 $pool->setSelectUsleepTime(400)

  • OPTION_DEBUG - 调试模式。启用一些执行调试消息输出。默认为false。此方法的别名是 $pool->setDebugEnabled(true)

  • OPTION_BLOCKING_MODE - 阻塞模式标志。如果使用阻塞模式,则在所有执行时间内进程将被停止。在其他情况下,当前进程可以与Future交互以等待结果或检查执行状态。默认为false,非阻塞模式。此方法的别名是 $pool->setBlockingMode(true)

命令选项

您可以通过两种方式配置与Pool相同的命令

$command = new rikanishu\multiprocess\Command(‘echoHello $NAME’’, [
	rikanishu\multiprocess\Command::OPTIONS_ENV => [
		‘NAME’ => ‘WORLD’,
	],
	rikanishu\multiprocess\Command::OPTIONS_CWD => ‘/tmp’
]);

或者

$command->setEnvVariables([
	‘NAME’ => ‘WORLD’,
]);
$command->setCwdPath(‘/tmp’);

您还可以在将shell命令作为数组第二个元素传递给Pool构造函数时控制选项

$cmd1 = ‘echo Hello!’;
$cmd2 = ['echo "$SOME_ENV_VAR" "$PWD"', [
    rikanishu\multiprocess\Command::OPTION_CWD => '/tmp',
    rikanishu\multiprocess\Command::OPTION_ENV =>  [
        'SOME_ENV_VAR' => 'PWD is:'
    ],
]];

$pool = new rikanishu\multiprocess\Pool([$cmd1, $cmd2]);
$pool->run();
选项列表
  • OPTION_ENV - 命令的环境变量列表。默认为null。此选项的别名方法是 $command->setEnvVariables([])

  • OPTION_CWD - 命令的当前工作目录。默认为null,CWD从父进程继承。此选项的别名方法是 $command->setCwdPath(‘/tmp’)

  • OPTION_PROC - proc_open命令的选项。请参见完整列表在 PHP 文档。此选项的别名方法是 $command->setProcOptions([])

  • OPTION_STDIN - 命令的stdin。此选项的别名方法是 $command->setStdin('')

  • OPTION_DONT_CHECK_RUNNING - 不要等待执行结束,不要检查进程状态以识别它是否运行或未运行,只需读取stdin/stdout并停止进程。在处理管道以在进程给出任何输出后停止执行进程时非常有用。此选项的别名方法是 $command->setDontCheckRunning(true)