質問
シェルスクリプトを呼び出す必要があるが、出力についてはまったく気にしないPHPスクリプトがあります。シェルスクリプトは多数のSOAP呼び出しを行い、完了するのに時間がかかるため、応答を待っている間にPHPリクエストを遅くしたくありません。実際、PHPリクエストはシェルプロセスを終了せずに終了できるはずです。
さまざまな exec()
、 shell_exec()
、 pcntl_fork()
などの関数を調べましたが、どれも彼らは私が欲しいものを正確に提供するようです。 (または、もしそうなら、それは私には明確ではありません。)提案はありますか?
解決
「出力を気にしない」場合、プロセスのバックグラウンドとして&
を使用してスクリプトのexecを呼び出すことはできませんか?
編集-@ AdamTheHut がこの投稿にコメントした内容を組み込み、これに追加できます。 exec
の呼び出し:
" > /dev/null 2>/dev/null &"
stdio
(最初の>
)と stderr
( 2>
)の両方をにリダイレクトします> / dev / null
をバックグラウンドで実行します。
同じことを行う方法は他にもありますが、これが最も読みやすいです。
上記の二重リダイレクトの代替:
" &> /dev/null &"
他のヒント
これには at を使用しました。実際には独立したプロセスを開始しています。
<?php
`echo "the command"|at now`;
?>
すべてのWindowsユーザーへ:非同期PHPスクリプトを実行する良い方法を見つけました(実際、ほとんどすべてで動作します)。
これは、popen()およびpclose()コマンドに基づいています。そして、WindowsとUnixの両方でうまく機能します。
function execInBackground($cmd) {
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
Linuxでは、次のことができます。
$cmd = 'nohup nice -n 10 php -f php/file.php > log/file.log & printf "%u" $!';
$pid = shell_exec($cmd);
コマンドプロンプトでコマンドを実行し、PIDを返すだけです。PIDは&gt;で確認できます。確実に機能するように0。
この質問は似ています: PHPにはスレッドがありますか
php-execute-a-background-process にはいくつかの良い提案があります。私はかなり良いと思うが、私は偏っている:)
Linuxでは、コマンドの最後にアンパサンドを追加することにより、新しい独立したスレッドでプロセスを開始できます
mycommand -someparam somevalue &
Windowsでは、&quot; start&quot;を使用できます。 DOSコマンド
start mycommand -someparam somevalue
それを行う正しい方法(!)は
- fork()
- setsid()
- execve()
fork forks、setsidは、現在のプロセスにマスタープロセス(親なし)になるように指示し、execveは、呼び出しプロセスを呼び出しプロセスに置き換えるように指示します。子に影響を与えずに親が終了できるようにします。
$pid=pcntl_fork();
if($pid==0)
{
posix_setsid();
pcntl_exec($cmd,$args,それを行う正しい方法(!)は
- fork()
- setsid()
- execve()
fork forks、setsidは、現在のプロセスにマスタープロセス(親なし)になるように指示し、execveは、呼び出しプロセスを呼び出しプロセスに置き換えるように指示します。子に影響を与えずに親が終了できるようにします。
<*>ENV);
// child becomes the standalone detached process
}
// parent's stuff
exit();
これを使用しました...
/**
* Asynchronously execute/include a PHP file. Does not record the output of the file anywhere.
* Relies on the PHP_PATH config constant.
*
* @param string $filename file to execute
* @param string $options (optional) arguments to pass to file via the command line
*/
function asyncInclude($filename, $options = '') {
exec(PHP_PATH . " -f {$filename} {$options} >> /dev/null &");
}
( PHP_PATH
は define( 'PHP_PATH'、 '/ opt / bin / php5')
などのように定義されたconst)
コマンドラインを介して引数を渡します。それらをPHPで読むには、 argv を参照してください。
本当に役立ったとわかった唯一の方法は次のとおりでした:
shell_exec('./myscript.php | at now & disown')
Symfonyプロセスコンポーネントも役立ちましたこのため。
use Symfony\Component\Process\Process;
$process = new Process('ls -lsa');
// ... run process in background
$process->start();
// ... do other things
// ... if you need to wait
$process->wait();
// ... do things after the process has finished
GitHubリポジトリで動作を確認してください。
名前付きfifoを使用します。
#!/bin/sh
mkfifo trigger
while true; do
read < trigger
long_running_task
done
その後、実行時間の長いタスクを開始したいときはいつでも、単に改行を書き込むだけです(トリガーファイルへの非ブロッキング。
入力が PIPE_BUF
より小さく、単一の write()
操作である限り、引数をfifoに書き込み、として表示させることができます。スクリプトの$ REPLY
。
PHPスクリプトをデーモンまたは cronjob として実行することもできます:#!/ usr / bin / php -q
キューを使用せずに、 proc_open()
このように:
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w") //here curaengine log all the info into stderror
);
$command = 'ping stackoverflow.com';
$process = proc_open($command, $descriptorspec, $pipes);