次のPHPコードは、約3.5秒のランタイムを返します(複数回測定され、平均化されます)。
_$starttime = microtime(true);
exec('/usr/local/bin/convert 1.pdf -density 200 -quality 85% 1.jpg');
$endtime = microtime(true);
$time_taken = $endtime-$starttime;
_
Sshターミナルで同じコマンドを実行すると、実行時間は約0.6秒に短縮されます(コマンドラインツールtime
で測定)。
Imagemagickライブラリのバージョンは
_Version: ImageMagick 6.7.0-10 2012-12-18 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2011 ImageMagick Studio LLC
Features: OpenMP
_
この時差の理由は何でしょうか?
ここスタックオーバーフローに関する同様の質問に対する1つの答えは、オーバーヘッドはWebサーバーがスレッド/シェルを開始しなければならないことに起因するというものでした。これが本当に理由でしょうか?スレッドは軽量で、開始/終了するのにそれほど時間はかからないと思いました。
exec
を呼び出す前に、imagemagickが使用するスレッドの数を(これはOpenMPのバグだったので、 参照 )exec('env MAGICK_THREAD_LIMIT=1');
で1に設定しました。 PHPからのランタイムは、_MAGICK_THREAD_LIMIT
_に設定した値に関係なく、あまり変化しません。とにかく、このバージョンのOpenMPにはバグがないようです。コマンドラインの実行は問題ありません。
上記のコマンドの実行時間を改善する方法についての提案をいただければ幸いです。
手伝ってくれてありがとうございます。
キーボードまたはsshを介してUnixマシンにログインすると、シェルの新しいインスタンスが作成されます。シェルは通常、_/bin/sh
_または_/bin/bash
_のようなものです。シェルを使用すると、コマンドを実行できます。
exec()
を使用すると、シェルの新しいインスタンスも作成されます。そのインスタンスは、送信されたコマンドを実行してから終了します。
シェルコマンドの新しいインスタンスを作成すると、独自の環境変数があります。したがって、これを行う場合:
_exec('env MAGICK_THREAD_LIMIT=1');
exec('/usr/local/bin/convert 1.pdf -density 200 -quality 85% 1.jpg');
_
次に、2つのシェルを作成すると、最初のシェルの設定が2番目のシェルに到達することはありません。 2番目のシェルで環境変数を取得するには、次のようなものが必要です。
_exec('env MAGICK_THREAD_LIMIT=1; /usr/local/bin/convert 1.pdf -density 200 -quality 85% 1.jpg');
_
さて、シェル自体が問題である可能性があると思われる場合は、シェルの作成に時間がかかりすぎるため、次のことを試してみてくださいknowほとんど時間がかかりません。
_$starttime = microtime(true);
exec('echo hi');
$endtime = microtime(true);
$time_taken = $endtime-$starttime;
_
その時点で、シェルのインスタンス化を高速化する方法を見つけようとする必要があります。
お役に立てれば!
私は56年以上コンピューターをプログラミングしてきましたが、このようなバグに遭遇したのはこれが初めてです。そのため、Perl
からphp
を介してexec
プログラムを実行する場合、Perl
プログラムを直接実行する場合と比較して、実行速度が7倍悪いことを理解するために1週間近く費やしました。コマンドライン。この取り組みの一環として、私はこの問題がWeb上で提起されたすべての時間についても詳しく調べました。これが私が見つけたものです:
(1)これは、2002年に最初に報告されたバグであり、その後11年間は修正されていません。
(2)このバグは、Apache
がphp
と相互作用する方法に関連しているため、これらの組織は両方とももう一方にお金を渡します。
(3)バグは、exec
、システム、またはその他のいずれでも同じです。
(4)バグは、実行されたプログラムがPerl
、exe
などであるかどうかに依存しません。
(5)バグはUNIXとWindowsで同じです。
(6)このバグは、imagemagick
または一般的な画像とは何の関係もありません。まったく異なる設定でバグに遭遇しました。
(7)このバグは、フォーク、シェル、bashなどの起動時間とは何の関係もありません。
(8)Apache
サービスの所有者を変更してもバグは修正されません。
(9)よくわかりませんが、サブルーチンを呼び出す際のオーバーヘッドの大幅な増加に関連していると思います。
この問題が発生したとき、40秒で実行されるPerl
プログラムがありましたが、exec
を介して304秒かかりました。私の究極の解決策は、プログラムを最適化して、直接0.5秒またはexec
を介して3.5秒で実行されるようにする方法を見つけることでした。だから私はその問題を解決しなかった。
@Philippは、SSHがあり、サーバーがexec()
へのアクセスを許可しているため、マシンへの完全なルートアクセスも持っていると想定します。
マシンへのルートアクセス権があるということは、_/etc/php5/php.ini
_メモリ制限設定を変更できることを意味します。
_/etc/php5/php.ini
_に直接アクセスしなくても、プロジェクトディレクトリに新しい_php.ini
_ファイルを作成することで、サーバーが_php.ini
_ディレクティブのオーバーライドをサポートしているかどうかを確認できます。
オーバーライドが許可されていない場合でも、AllowOverride
がAll
の場合は、メモリ設定を_.htaccess
_から変更できます。
メモリ制限を変更するさらに別の方法は、ini_set('memory_limit', 256);
を使用してPHPランタイム中に設定することです。
exec()
を介して変換を実行することの唯一の良い点は、exec()
から結果を取得して、非同期で実行できるようにする予定がない場合です。
_exec('convert --your-convert-options > /dev/null 2>/dev/null &');
_
上記のアプローチは、多くのファイルをバッチ処理しようとしている場合、ファイルの処理が完了するのを待ちたくない場合、および各ファイルが処理されたことを確認する必要がない場合に通常役立ちます。
上記のコードを使用して単一のファイルを処理するためにexec
をasync
で実行すると、PHP内でGd/Imagickを使用するよりもプロセッサ時間とメモリが多くなります。時間/メモリは、PHPプロセス(訪問者にサイトの移動が速くなるように感じさせる)に影響を与えない別のプロセスによって使用されますが、メモリ消費が存在し、多くの処理に関してはカウントされる接続。
これはPHPバグではなく、Apache/Nginxやその他のWebサーバーとは何の関係もありません。
私は最近同じ問題を抱えていて、exec()の実装をチェックするためにPHPソースコードを調べました。
基本的に、PHPのexec()はLibcのpopen()関数を呼び出します。
ここでの違反者はCのpopen()で、非常に遅いようです。 「cpopenslow」をグーグルですばやく検索すると、あなたのような質問がたくさん表示されます。
また、このパフォーマンスの問題を克服するために、誰かがCでpopen_noshell()という関数を実装していることもわかりました。
https://blog.famzah.net/2009/11/20/a-much-faster-popen-and-system-implementation-for-linux/
これは、速度の違いとpopen()およびpopen_noshell()の違いを示すスクリーンショットです。
PHPのexec()は、通常のpopen()を使用します。これは上のスクリーンショットの右側にあります。ご覧のとおり、Cのpopen()を実行するときにシステムが使用するCPUは非常に高くなっています。
この問題には2つの解決策があります。
追記:
これを検索しているときに、Cのものと同じ名前のPHP関数を発見しました:popen()
Pclose(popen( 'your command'、 'r'));を使用して、外部コマンドを非同期で実行できるので興味深いです。
これは基本的にexec( 'your command&');と同じ効果があります。
exec
を呼び出すと、phpはスレッドを作成せず、新しい子プロセスを作成します。新しいプロセスの作成は大きなオーバーヘッドです。
ただし、sshに接続するときは、実行するコマンドを渡すだけです。あなたはそのプログラムの所有者ではないので、あなたが接続したユーザーとして実行されます。 exec
の場合、PHPを実行するユーザー。
私はこの問題を経験しました。コマンドラインから実行すると約.025秒かかるグラフィック処理コマンドは、PHPのexec()から呼び出すと約.3秒かかりました。多くの調査の結果、ほとんどの人がこれがApacheまたはPHPの問題であると信じているようです。次に、PHPを完全にバイパスして、CGIスクリプトを介してコマンドを実行しようとしましたが、同じ結果が得られました。
したがって、問題はApacheにあるはずなので、lighttpdをインストールしても、同じ結果が得られました。
いくつかの考えと実験の後、私はこれがプロセッサの優先順位の問題であるに違いないことに気づきました。したがって、コマンドをコマンドラインと同じ速度で実行する場合は、次のように実行する必要があります。
exec('echo "password" | Sudo -S Nice -n -20 command')
注意:これにはあらゆる種類のセキュリティ上の反対意見があることを私は知っています。私はあなたがしなければならないのはあなたの命令の前にニースを加えることだけであるという答えに単に焦点を合わせたかっただけです。