Devel::Cycleがいい感じ。
id:yumatsumoさんのところで触れられているTemplate::Plugin::Filterのメモリリーク問題ですが、Devel::Cycleをためそうとして諸事情(?)によりためせなかったのですが改めて試してみるといい感じです。
まずはリークするソース
package Template::Plugin::Leak; use strict; use base 'Template::Plugin::Filter'; sub init { my $self = shift; # first arg can specify filter name $self->install_filter($self->{ _ARGS }->[0] || 'leak'); return $self; } sub filter { my ($self, $text, $args, $config) = @_; return uc $text; } 1
利用側のコード
use strict; use Template; use lib 'lib'; use Devel::Cycle; my $template =<<__TEMPLATE__; [% USE Leak %] [% FILTER leak %] lower case characteres [% END %] __TEMPLATE__ my $tt = Template->new(); $tt->process( \$template ) or die $tt->error; find_cycle( $tt );
実行結果
Cycle (1): $Template::A->{'SERVICE'} => \%Template::Service::B $Template::Service::B->{'CONTEXT'} => \%Template::Context::C $Template::Context::C->{'LOAD_FILTERS'} => \@D $D->[0] => \%Template::Filters::E $Template::Filters::E->{'FILTERS'} => \%F $F->{'leak'} => \&G $G variable $self => \%Template::Plugin::Leak::H $Template::Plugin::Leak::H->{'_CONTEXT'} => \%Template::Context::C Cycle (2): $Template::A->{'SERVICE'} => \%Template::Service::B $Template::Service::B->{'CONTEXT'} => \%Template::Context::C $Template::Context::C->{'LOAD_FILTERS'} => \@D $D->[0] => \%Template::Filters::E $Template::Filters::E->{'FILTERS'} => \%F $F->{'leak'} => \&G $G variable $self => \%Template::Plugin::Leak::H $Template::Plugin::Leak::H->{'_STATIC_FILTER'} => \&G
最後の2行あたりでG <-> Hで循環しているというのがよくわかります。ちゃんと{_STATIC_FILTER}も検出してくれていますし。
全体的に見るにはDevel::Leak::Objectで、場所を特定するのにDevel::Cycleでと使い分けると便利かも。
Devel::Cycleをテストハーネスに組み込んでくれるモジュールhttp://search.cpan.org/~petdance/Test-Memory-Cycle-1.04/もあるらしく、これを習慣付けるといいなぁと思って試してみると以下のエラーがでていることに気づく。(もともと出ていたみたいだったけど望みどおりの結果で満足してスルーしていた・・・)
Not a SCALAR reference at /usr/local/share/perl/5.8.8/Devel/Cycle.pm line 124.
調べてみるとバグレポートがでていて、クロージャがらみのエラーのようだ。
http://rt.cpan.org/Public/Bug/Display.html?id=25360
パッチが添付されてされていたので試してみたけど
Undefined subroutine &Devel::Cycle::_find_cycle_ called at /usr/local/share/perl/5.8.8/Devel/Cycle.pm line 98.
といって怒られた。
もう眠いので今日は断念。
[Perl]更新の有無をチェックするならstatよりファイルテストが高速
キャッシュ更新のためとかでファイルの更新日時をチェックする時はstatよりファイルテストの方がかなり高速
use strict; package Bench; my $file = '/tmp/hoge'; sub bench_stat { my $last_update = (stat $file)[9]; } sub bench_file_test { my $day = -M $file; } sub bench_stat_with_size { my ( $size, $last_update ) = (stat $file)[7,9]; } sub bench_file_test_with_size { my ( $day, $size ) = (-M $file, -s _); } package main; use Benchmark qw(timethese cmpthese); use Class::Inspector; my $meth = Class::Inspector->methods('Bench'); my $b = timethese( 500000, { map { $_ => Bench->can($_) } grep /^bench_/, @$meth }); cmpthese($b);
>|shell||
Benchmark: timing 500000 iterations of bench_file_test, bench_file_test_with_size, bench_stat, bench_stat_with_size...
bench_file_test: 1 wallclock secs ( 0.23 usr + 0.81 sys = 1.04 CPU) @ 480769.23/s (n=500000)
bench_file_test_with_size: 2 wallclock secs ( 0.40 usr + 0.86 sys = 1.26 CPU) @ 396825.40/s (n=500000)
bench_stat: 2 wallclock secs ( 1.14 usr + 0.86 sys = 2.00 CPU) @ 250000.00/s (n=500000)
bench_stat_with_size: 3 wallclock secs ( 1.26 usr + 0.92 sys = 2.18 CPU) @ 229357.80/s (n=500000)
Rate bench_stat_with_size bench_stat bench_file_test_with_size bench_file_test
bench_stat_with_size 229358/s -- -8% -42% -52%
bench_stat 250000/s 9% -- -37% -48%
bench_file_test_with_size 396825/s 73% 59% -- -17%
bench_file_test 480769/s 110% 92% 21% --
|
[JavaScript][Ext]フォームコントロールと入力チェック
htmlでデザインしたページにExtのリッチコントロール機能を付加するサンプル。簡単な解説はこちらでしています・・・usuilog-プログラミングメモ: [JavaScript][Ext]Ext.jsのフォームコンポーネントと入力チェック
htmlソース
<html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>Form Control Example</title> <script src="ext-1.1-beta1/adapter/yui/yui-utilities.js" type="text/javascript" charset="utf-8"></script> <script src="ext-1.1-beta1/adapter/yui/ext-yui-adapter.js" type="text/javascript" charset="utf-8"></script> <script src="ext-1.1-beta1/ext-all-debug.js" type="text/javascript" charset="utf-8"></script> <script src="ext-1.1-beta1/source/locale/ext-lang-ja.js" type="text/javascript" charset="utf-8"></script> <script src="formsample.js" type="text/javascript" charset="utf-8"></script> <link rel="stylesheet" href="ext-1.1-beta1/resources/css/ext-all.css" type="text/css" media="screen" charset="utf-8" /> <link rel="stylesheet" href="ext-1.1-beta1/resources/css/ytheme-aero.css" type="text/css" media="screen" charset="utf-8" /> </head> <body> <form id="form1" name="form1"> <fieldset id="fxtest"> <legend>Ext form control example</legend> <dt><label for="name-input">お名前</label></dt> <dd> <input type="text" id="name-input" name="name" /> </dd> <dt><label for="url-input">URL</label></dt> <dd> <input type="text" id="url-input" name="url" /> </dd> <dt><label for="mail-input">メールアドレス</label></dt> <dd> <input type="text" id="mail-input" name="mail" /> </dd> <dt><label for"blood-select">血液型</label></dt> <dd> <select name="blood" id="blood-select"> <option value="">選択してください</option> <option value="A">A</option> <option value="B">B</option> <option value="O">O</option> <option value="AB">AB</option> </select> </dd> <dt><label for"birth-input">生年月日</label></dt> <dd> <input type="text" id="birth-input" name="birth" /> </dd> <dt><label for"income-input">希望年収</label></dt> <dd> <input type="text" id="income-input" name="income" />万円 </dd> <dt><label for"carrier-area">経歴</label></dt> <dd> <textarea id="carrier-area" cols="50" rows="10" name="carrier"></textarea> </dd> <dt><label for"promotion-area">自己PR</label></dt> <dd> <textarea id="promotion-area" cols="50" rows="10" name="promotion"></textarea> </dd> <div id="submit-button"></div> </fieldset> </form> </body> </html>
JavaScriptソース
Ext.onReady(function(){ // 入力エラー時のツールチップを有効にする Ext.QuickTips.init(); var name = new Ext.form.TextField({ allowBlank: false }); name.applyTo('name-input'); var url = new Ext.form.TextField({ allowBlank: false, vtype: 'url' // SEE ALSO Ext.form.VTypes }); url.applyTo('url-input'); var mail = new Ext.form.TextField({ allowBlank: false, // Custom validation validator: function(fvalue) { // Ext.form.VTypesより。@の前の.も許可 var email = /^([\w]+)(.[.\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/; if (email.test(fvalue)) { return true; } return String.format('{0}はメールアドレスとして正しくありません。', fvalue) + Ext.form.VTypes.emailText; } }); mail.applyTo('mail-input'); // 数字だけしか入力できない(automatic keystroke filtering // 日本語は防げないみたい var income = new Ext.form.NumberField({ allowBlank: false }); income.applyTo('income-input'); var date = new Ext.form.DateField({ allowBlank:false, format: 'Y/m/d' }); date.applyTo('birth-input'); var combo = new Ext.form.ComboBox({ typeAhead: true, triggerAction: 'all', width:135, forceSelection:true, transform: 'blood-select' }); var carrier = new Ext.form.TextArea({ grow: true, // 入力量に応じてテキストエリアが拡張される growMax: 200 }); carrier.applyTo('carrier-area') var promo = new Ext.form.HtmlEditor({ width: 600, height: 300 }); promo.applyTo('promotion-area'); var submit = new Ext.Button('submit-button', { text: '送信' }); submit.on('click', function(e,t) { var str = Ext.Ajax.serializeForm('form1'); alert(str); } ); submit.show(); });
splitの高速化
splitも中で配列を作ってるんじゃなかろうかと思いまして正規表現でパースしたのと比較してみました。
・・・中略・・・
微妙な差ですな。
訂正 2007/06/25
うちの環境では結構差がでました。
ちなみに正規表現を最小マッチにしたらもう気持ち早くなりました。
sub parse_regexp_min_match { $_[0] =~ /^(.+?)\t(.+?)\t(.+?)\t(.+)/; return ($1, $2, $3, $4); }
Benchmark: timing 1000 iterations of regexp, regexp_min_match, split... regexp: 6 wallclock secs ( 6.86 usr + 0.00 sys = 6.86 CPU) @ 145.77/s (n=1000) regexp_min_match: 6 wallclock secs ( 6.03 usr + 0.00 sys = 6.03 CPU) @ 165.84/s (n=1000) split: 15 wallclock secs (14.21 usr + 0.00 sys = 14.21 CPU) @ 70.37/s (n=1000) Rate split regexp regexp_min_match split 70.4/s -- -52% -58% regexp 146/s 107% -- -12% regexp_min_match 166/s 136% 14% --
コメントで頂いたとおり結果がまるで出鱈目だった為再計測しました。
ついでに第3引数指定した場合のsplitも追加。これはあまり変わりませんでした。
正規表現との比較では普通の正規表現ではsplitの方が高速ですが、最小マッチにすると正規表現が上回りました。
環境はperl5.8.8 Celeron1.80GHzです。
#!/usr/local/bin/perl use strict; use Benchmark qw(:all); chomp (my @list = map { s/ +/\t/g; $_ } <DATA>); # 運命の5,000王子 my @large_list = (@list) x 1000; sub parse_split { return split "\t", $_[0]; } sub parse_split_3 { return split "\t", $_[0], 4; } sub parse_regexp { $_[0] =~ /^(.+)\t(.+)\t(.+)\t(.+)/; return ( $1, $2, $3, $4); } sub parse_regexp_min_match { $_[0] =~ /^(.+?)\t(.+?)\t(.+?)\t(.+)/; return ( $1, $2, $3, $4); } my $res = Benchmark::timethese(1000, { "split" => sub { parse_split($_) for @large_list }, "split_3" => sub { parse_split_3($_) for @large_list }, "regexp" => sub { parse_regexp($_) for @large_list }, "regexp_min_match" => sub { parse_regexp_min_match($_) for @large_list }, }); Benchmark::cmpthese($res); __DATA__ マリポーサ メキシコ 100000000 偽マッスルリベンジャー アタル キン肉星 1080000 ナパームストレッチ ビッグボディ カナダ 100000000 メイプルリーフクラッチ スーパーフェニックス オーストラリア 100000000 マッスルリベンジャー ゼブラ ナムビア 100000000 マッスルインフェルノ
Benchmark: timing 1000 iterations of regexp, regexp_min_match, split, split_3... regexp: 30 wallclock secs (30.02 usr + 0.01 sys = 30.03 CPU) @ 33.30/s (n=1000) regexp_min_match: 17 wallclock secs (17.14 usr + 0.00 sys = 17.14 CPU) @ 58.34/s (n=1000) split: 21 wallclock secs (20.72 usr + 0.00 sys = 20.72 CPU) @ 48.26/s (n=1000) split_3: 19 wallclock secs (19.35 usr + 0.00 sys = 19.35 CPU) @ 51.68/s (n=1000) Rate regexp split split_3 regexp_min_match regexp 33.3/s -- -31% -36% -43% split 48.3/s 45% -- -7% -17% split_3 51.7/s 55% 7% -- -11% regexp_min_match 58.3/s 75% 21% 13% --
Spket IDE
http://journal.mycom.co.jp/news/2007/06/20/033/index.html
1.5.11では新しくExtJS 1.1の開発機能が追加された
Demo:http://www.spket.com/demos/extjs.html
コード補完とかAPIドキュメントがポップアップで出たりとかクラス定義に飛べたりとか便利。
Ext.jsでAjaxその2
Ext.element.load。要素を指定して結果で内容を置き換えます。サーバがhtml部品で返してくる場合はこれが一番簡単かな。
var elem = Ext.get('test_elem'); elem.load( 'test', {param1: 'value1'}, // これを渡すとPOST。GETにしたいときはURLにくっつける function(elem, success) { if (success) { Ext.MessageBox.alert('Result', 'Success'); } else { Ext.MessageBox.alert('Result', 'Error'); } } ); elem.show();
Ext.jsでAjaxその1
ベースライブラリを直接利用するパターン。1.1以降はExt.Ajaxになるみたい。
var ajax = Ext.lib.Ajax.request( 'GET', '/test?' + param_string, { success: function (res, args) { var text = res.responseText; // 何らかの処理 }, failure: function (res, args) { var text = res.responseText; // 何らかの処理 }, } );