9

私はPerlで書いているフレームワークのパフォーマンスをベンチマークしてきましたが、既存のコードベースに比べて1秒あたりのリクエスト数が50%減少しています(手続き型スパゲッティコードからOOP MVCフレームワーク)。

アプリケーションはmod_perlで実行されており、 Mooseとすべてのフレームワークコードをstartup.plスクリプトに追加しました。これにより、1秒あたりのリクエスト数が2倍になりました。この数をさらに増やして、既存の量にできるだけ近づけることを目指しています。これは時期尚早の最適化であるという議論がありますが、修正してパフォーマンスにどのように影響するかを確認したいいくつかの明白な非効率性があります。

ほとんどのフレームワークと同様に、構成ファイルとディスパッチャーがあります。構成部分はConfig::Generalによって処理されるため、構成ファイルをアプリにロードするには、少しのIOと解析が必要です。ここで私が目にする最大の問題は、入ってくるすべてのリクエストに対してこれを行っていることです。

私のアプリでDevel::Dprofを実行すると、Mooseではない主要な低速ポイントの1つとして、Config :: General::BEGINと関連するIOモジュールの束が示されます。だから私がやりたいこと、そして後から考えるともっと理にかなっているのは、mod_perlの永続性とstartup.plコンパイルのものを利用して、サーバーの起動時に一度だけ構成ファイルにロードする作業を行うことです。

問題は、これがどのように機能するかについて私があまりよく知らないということです。

現在、各プロジェクトには、かなり無駄のない、次のようなPerlHandlerブートストラップクラスがあります。

use MyApp; 
MyApp->new(config_file => '/path/to/site.config')->run();

MyApp.pmは、次のコードを持つフレームワークProjectモジュールを継承します。

my $config = Config::General->new(
                -ConfigFile => $self->config_file,
                -InterPolateVars => 1,
             );    

$self->config({$config->getall});

コンパイル時にのみこれを行うには、ブートストラップとプロジェクトの両方のベースモジュールを変更する必要があります(私は思います)が、どのような変更を加えれば、コードを適切で無駄のないものに保つことができるかについてはかなりわかりません。誰かが私をここで正しい方向に向けることができますか?

アップデート

ysthの回答で説明されているように、各プロジェクトモジュールアプローチでBEGINBLOCKを試しました。だから私は今持っています:

package MyApp::bootstrap;
use MyApp;

my $config;
BEGIN
{
    $config = {Config::General->new(...)->getall};        
}

sub handler { ..etc.
    MyApp->new(config => $config)->run();

この迅速な変更だけで、1秒あたりのリクエスト数が50%増加し、構成ファイルが修正する価値のある主要なボトルネックであるという私の考えを確認しました。私たちの股間の古い開発マシンのベンチマーク値は60rpsであり、この変更だけで私のフレームワークは30rpsから45rpsになりました。Mooseが遅く、コンパイル時間がヒットしていると言う人のために..起動時にすべてのMooseコードをコンパイルすると、構成ファイルを事前コンパイルしたときと同じ(50%)増加しました。

私が今抱えている唯一の問題は、同じConfig :: General-> newコードがすべてのBEGINブロックにあり、構成ファイルへのパスのみが異なるため、これがDRYプリンシパルに違反することです。これを制限するためのいくつかの異なる戦略がありますが、この変更の結果を投稿したかっただけです。

4

6 に答える 6

10

アプリケーションが構成をまったく変更しないと仮定して、それを開始ブロックに移動します。

# this code goes at file scope
my $config;
BEGIN {
    $config = { Config::General->new( ... )->getall }
}

# when creating a new instance
$self->config( $config );

そして、すべてのモジュールがstartup.plにコンパイルされていることを確認してください。

より洗練されたものになり、シングルトンクラスに構成ハッシュを提供させることもできますが、その必要はありません。

于 2008-12-04T23:55:28.860 に答える
4

Moose のクラスをimmutableにできれば、速度がさらに向上する可能性があります。

于 2008-12-05T13:13:51.007 に答える
3

モジュールのインポートサブはコンパイル時に実行されるため、これを使用してysthの回答のDRYを削減/排除できます。

次の例では、importメソッドを使用して、指定された引数を含む構成ファイルを読み取り、その構成を呼び出し元のパッケージにプッシュします。

呼び出し元のパッケージ内の変数であるという警告は$config、これによって一掃されます。

package Foo_Config;
use English qw(-no_match_vars);
sub import {
   my ($self, @cfg) = @ARG;
   my $call_pkg     = caller;
   my $config       = {Config::General->new(@cfg)->getall};
   do{ # this will create the $config variable in the calling package.
       no strict 'refs';
       ${$call_pkg . '::config'} = $config;
   };
   return;
}

package MyApp;
# will execute Foo_Config->import('/path/to/site.config') at compile time.
use Foo_Config '/path/to/site.config'; 
于 2009-07-16T16:14:29.413 に答える
1

HTML::Mason フレームワークのインストールで同じ問題が発生しましたが、これはかなりうまく機能することがわかりました。

PerlRequire handler.pl
<FilesMatch "\.mhtml$">
  SetHandler perl-script
  PerlHandler YourModule::Mason
</FilesMatch>

handler.pl ファイルで、構成、データベース ハンドルなどのすべての静的項目を定義します。これにより、Apache スレッドの開始時にコンパイルされる YourModule::Mason のスコープでそれらが定義されます (新しいスレッドには明らかに固有のオーバーヘッド)。YourModule::Mason にはhandler、リクエストを処理するメソッドがあります。

HTML::Mason で起こっているいくつかの魔法がこれを助けていることは認めますが、それは私にとって、おそらくあなたにとってはうまくいきますか?

于 2008-12-05T00:54:33.653 に答える
0

わずかな変更でこのような処理を高速化する一般的な方法は、単純にグローバル変数を使用し、同じ Apache プロセスの呼び出し間で状態をキャッシュすることです。

use vars qw ($config);
# ...
$config = Config::General->new( ... )->getall
    unless blessed($config); # add more suitable test here

それはあまりきれいではなく、あいまいなバグにつながる可能性があり (私の経験では "my $var" がより多くの原因になりますが)、多くのメモリを消費することもありますが、多くの (繰り返される) 高価な初期化ステートメントはこの方法で回避できます。BEGIN{} を使用する場合の利点。コードのみで、Apache を再起動したり、プロセスを強制終了したりする必要なく、他のイベントに基づいて再初期化することもできます (たとえば、上記のテストでディスク上のファイルのタイムスタンプを含めることにより)。

ただし、落とし穴に気をつけてください:侵入する簡単な方法

于 2008-12-22T15:31:09.973 に答える
-2

JackM の考えは正しい。

すべてのクラスをロードし、アプリケーション レベルのオブジェクト (この場合は構成) を "マザー" Apache プロセスでインスタンス化することにより、新しいワーカーが生成されるたびにそれらをコンパイルする必要がなくなります。そして記憶に。私たちの間で非常に細心の注意を払って、アプリケーションが定期的に使用するすべてのモジュールに「使用」行を追加します。パッケージとモジュールをマザー シップにロードしない場合、各ワーカーはモジュールのロードによるパフォーマンス ヒットを受けるだけでなく、最新のオペレーティング システムが提供するメモリ共有の利点も得られません。

mod_perl と CGI の違いの残り半分です。前半は mod_perl の永続的な perl エンジンと、呼び出しごとの CGI の respawning perl です。

于 2008-12-05T13:24:56.650 に答える