通过PHP运行两个linux命令,在执行第二个之前不要先等待结束

时间:2015-03-15 00:43:53

标签: php linux bash centos centos6

这很奇怪,我搜索并尝试了所有内容,但我认为我只是在这里犯了一个愚蠢的语法错误。

我试图在CPU上运行压力测试,然后通过PHP立即将其CPU使用率限制为30%。该测试也在另一个用户下运行,并且具有指定的名称,因此可以对其进行限制。压力测试开始很好,但我可以看到PHP文件仍在加载,并且它结束了压力测试结束的第二个。

以下是我尝试过的一些方法

$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30"');

$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s > /dev/null & cpulimit -e MyUniqueProcessName -l 30"');

这样做的全部目的是因为我正在为游戏托管网站编写脚本,我想限制每台服务器的资源消耗以提高质量,而不是让某人占用所有资源。 基本上,游戏服务器将运行而不是压力测试。

编辑::

这就是我现在所拥有的:

我需要在"测试"下运行压力。 ,但是在sudo apache或root下的cpulimit,因为它需要特殊权限。压力仍然开始很好,但它吃了99.9%

passthru('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s &" & sudo cpulimit -e MyUniqueProcessName -l 30 -i -z');

执行此操作后,我无法在流程列表中看到cpulimit http://i.imgur.com/iK2nL43.png

1 个答案:

答案 0 :(得分:0)

不幸的是,&&或多或少与您想要的相反。 :-)当你在Bash中A && B时,这意味着,"运行命令A并等到它完成;如果成功,则运行命令B。"

相比之下,A & B表示,"运行命令A,然后立即运行命令B."

所以你在你的命令中接近正确,但只是使用两个bash命令(应该只需要一个)和&&来绊倒。

另外,您是否尝试在两个终端中在PHP之外单独运行每个命令?我刚刚下载并构建了stresscpulimit(我假设这些是您正在使用的?),单独运行命令,并发现问题:cpulimit仍然不是&{限制百分比。

查看stress的文档,我发现它可以通过分支子进程来工作,因此您尝试CPU限制的那个是父进程,但那不是使用的进程CPU。 cpulimit --help显示了-i选项,其中包含有限的子进程。

这让我能够在一个终端输入此内容(第一行显示提示输入;后续显示输出):

$> exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i
[1] 20229
MyUniqueProcessName: info: [20229] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
Process 20229 found

然后,在另一个运行top的终端中,我看到了:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM     TIME+ COMMAND
20237 stackov+  20   0  7164  100    0 R 30.2  0.0   0:04.38 stress

好多了。 (请注意,在使用exec -a对其进行别名的Bash shell之外,您会看到进程名称为stress。)不幸的是,我还看到另一个问题,即剩余cpulimit&# 34;听音"用于具有该名称的更多进程。返回cpulimit --help,其中显示-z选项。

只是为了降低复杂性,你可以通过特殊的Bash变量stress来关闭别名并使用$!进程的PID,它引用最后一个进程的PID推出。在终端中运行以下内容似乎可以完成您想要的一切:

stress -c 1 -t 60s & cpulimit -p $! -l 30 -i -z

现在,只需使用我们学到的知识更改PHP脚本:

exec('bash -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i -z"');

......或更简单的版本:

exec('bash -c "stress -c 1 -t 60s & cpulimit -p \$! -l 30 -i -z"');

(请注意$!中的$必须使用反斜杠\$!进行转义,因为它在传递给bash -c时的引用方式。)

最终答案:

根据你修改问题的最后一个例子,你会想要这样的事情:

passthru('bash -c "sudo -u test stress -c 1 -t 60s & sudo -u root cpulimit -p \$! -l 30 -i -z"');

当我使用php stackoverflow-question.php运行时,会输出以下内容:

stress: info: [3374] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
stress: info: [3374] successful run completed in 60s
Process 3371 found

(在PHP脚本完成后,第二行出现,所以不要误导。使用top进行检查。)

在PHP脚本运行的60秒内在另一个终端运行top,我看到了:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM     TIME+ COMMAND
 3472 test      20   0  7160   92    0 R 29.5  0.0   0:07.50 stress
 3470 root       9 -11  4236  712  580 S  9.0  0.0   0:02.28 cpulimit

这正是您所描述的想法:stress正在用户test下运行,而cpulimit正在用户root下运行(两者都是如果需要,您可以在命令中更改)。 stress限制在30%左右。

我不熟悉runuser并且没有看到适用性,因为sudo是以另一个用户身份运行流程的标准方式。要使其工作,您可能必须在/ etc / sudoers中调整您的设置(这将需要root访问权限,但您显然已经拥有了该设置)。这完全超出了本次讨论的范围,但作为一个例子,我添加了以下规则:

my-user ALL=(test) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/stress 
my-user ALL=(root) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/cpulimit