ついったー
今更感があるものの,とりあえず登録してみた.
http://twitter.com/mikage
しかし・・・身の回りでついったーしている人ってほとんどいない気が(^^;
lists:keymemberこれは関数名からは何をするのかよく分からなかったので、ドキュメントを見たのですが、それでもよく分からない・・・
指定したキーを持つタプルが存在するか調べるために使うものかと思います.
1> lists:keymember("mocha", 1, [{"cinnamon", 1}, {"mocha", 2}, {"milk", 3}]).
true
2> lists:keymember("cappuccino", 1, [{"cinnamon", 1}, {"mocha", 2}, {"milk", 3}]).
false
こんな感じでしょうか.
lists:key~ を使えば,Perlなどのハッシュに相当する処理を行える(もちろん処理時間は異なるけれど),ということだと思います.
1> X1 = [].
[]
2> X2 = lists:merge(X1, [{"cinnamon", 1}, {"mocha", 2}]).
[{"cinnamon",1},{"mocha",2}]
3> lists:keysearch("mocha", 1, X2).
{value,{"mocha",2}}
4> X3 = lists:keydelete("mocha", 1, X2).
[{"cinnamon",1}]
5> lists:keysearch("mocha", 1, X3).
false
margeを使ってキーを追加,キーの上書きは keyreplace,取得は keysearch,存在確認は keymember,削除は keydelete,ソートは keysort で出来るようです.
タプルの数に比例して処理時間がかかると思うので,要素数が少ない場合にしか使えないとは思いますが・・・
JavaScriptベースのチャットを作るとき,Cometを使うのが一般的とされているようだけど,もっと楽な方法でも良さそうに思える.
Cometでは1回リクエストを受け取るたびにコネクションを切断しているので,Keep-aliveなどと併用しなければならない.
実際に都度TCP接続を張り直すとコストが大きいので,Keep-Aliveを併用したりする必要があるものの,それも色々裏技的な回避をしないとだめな模様.
(Cometの正しい使い方を参照)
でも,チャットを実装する上では,都度コネクションを切断する必要がなさそうに思える.
iframeで別のページを読み込み,その中で script タグを使って親フレームを更新するだけではダメなのだろうか.
この方法であれば,
・Cometのように,切断してから再接続するまでのタイムラグがないので,サーバ側の余計な処理が減る.(切断中に届いたメッセージを探す動作などが不要)
・サーバに再接続しないので,サーバ側からのpushが連続したときでも余計なタイムラグが発生しない.
・Keep-AliveやPipeliningなどとの相性問題の心配が不要
といった点でメリットがありそう.
実際にサンプルを作ってみると,
chat.html
chat.cgi (ソース)
こんな感じでちゃんと動く.
ただ,Comet+JSONPならメインのドメインとは別のドメインで接続が出来るけど,この方法ではクロスドメイン制約にひっかかって無理.
しかし,ページ自体を複数ドメインにすれば簡単に回避できるはず.
(チャットルームごとに http://部屋名.example.com/ のURLを使うとか)
Cometのメリットがこれだけなら,多くのケースでは接続しっぱなしの方が実装も楽で良さそうに思うけど,何か見落としているのかなぁ?
Cometのページを見ても,その辺に関しての記述は見つけられなかった...
それとも,Amazonアフィリエイトみたいな事をやろうとするときに,メインのページが固定ドメインでないと不都合がありそうなので,そこが重要だったりするのだろうか…
(とりあえず気になったので,Amazonに http://*.example.com/ のような形で登録できるか聞いてみた.返事待ち)
----
追記.
今更1つ大きな違いに気づいた.
iframeでは,ブラウザのロード中の表示が継続してしまう.
IEだとあまり気にならないけど,Firefoxとかでは結構気になる.
Cometであれば,見た目は変わらないので,やっぱりそこがメリットなのかな.
GmailもどうやってるのかFirebugで見てみたら,Cometっぽい感じだった.
だいたい200秒くらいでタイムアウトして,新しく接続し直している感じ.
----
さらに追記.
久しぶりにはてブを見てみたら,コメントがあった.
throbber が回ることさえ気にしないのなら、それでOK。切断時の対応コードを含めると、コード量はかわらないと思う。iframe なら document.domain 操作でサブドメイン越えが可能
とあった.
まぁ,ぐるぐる回るのは一度気づいてしまうと気になって仕方ないので,無しかなぁ.
Rails って,結構人気があるから,既にそういう機能もあるのではと思っていたけど,無かったらしい.
簡単に実装できるから,誰も公開していなかっただけなのかもしれないけど.(^^;
2種類のモジュールがあるようだけど,readonlyable 方式はすぐ問題が出てきそうな気がする.
たとえば,ユーザ登録時にIDの重複判定をするような場合,read_only 指定をしていると,masterからslaveへの更新反映が遅延するため,正しく重複判定出来ない可能性が出てしまいそう.
かといって,read_only 指定をしないと,アクセスが多そうなユーザ情報のテーブルが分散されない.
その辺を考えると,多少面倒でも magic_multi_connections のやり方が正解じゃないのかなぁ,と思う.
TripletaiL でも,こういう分散は考慮していて,magic_multi_connections と同じようなやり方を採用している.
ただし,複数のサーバを登録しておいて,ラウンドロビンで適当なDBを使う機能がついているので,コード側ではマスターかスレーブかを指定しておいて,複数台のスレーブの分散はフレームワーク任せという感じ.
縦の分散だけじゃなく,横の分散まで自動化できるツールがあると便利そうだけど,見たことがない….
実装,というか上手く分散するロジックを考えるのが難しいからかなぁ.
% 分散DBを使う方がお手軽?ErlangのMnesiaに期待中…
そもそもはじめからUTF-8、それもutf8フラグがたっている文字列にfrom_toを使うのはばかげている。とのことだけど,utf8フラグは立っていない想定.
my $dec = find_encoding("UTF-8"); my $enc = find_encoding("Shift_JIS"); my $str = "123あいう"; for(my $i = 0; $i < 0xffff; $i++) { $enc->encode($dec->decode($str)); }
方法 | 言語 | 時間(sec) |
---|---|---|
iconv | Erlang (beam) | 0.604394 |
Erlang (native) | 0.612490 | |
Erlang (beam+smp) | 1.232886 | |
Erlang (native+smp) | 1.250170 | |
Unicode::Japanese | Perl | 0.646837 |
Encode | Perl | 1.403991 |
Encode(改) | Perl | 0.151645 |
driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING
int control(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen) This is a special routine invoked with the erlang function port_control/3. It works a little like an "ioctl" for erlang drivers. The data given to port_control/3 arrives in buf and len. The driver may send data back as a driver binary, using *rbuf and rlen. This is the fastest way of calling a driver and get a response. It won't make any context switch in the erlang emulator, and requires no message passing. It is suitable for calling C function to get faster execution, when erlang is too slow.
方法 | 言語 | 時間(sec) |
---|---|---|
parser | Erlang (beam) | 2.843180 |
Erlang (native) | 1.079725 | |
Erlang (beam+smp) | 3.035176 | |
Erlang (native+smp) | 0.776946 | |
正規表現 | Perl | 0.197326 |
-module(strparser). -export([bench/0, bench/1]). bench() -> Time = timer:tc(strparser, bench, [16#ffff]), io:format("~w~n", [Time]). bench(0) -> 0; bench(N) -> String = "12.34.123.12 - - [17/Apr/2007:23:53:13 +0900] \" GET /html/1234.html HTTP/1.1\" 200 6980 \"http://www. mikage.to/html/1234.html\" \"Mozilla/4.0 (compatible; MS IE 6.0; Windows NT 5.1; SV1)\"\n", {Str1, Str2} = parser:parse(parser:pAnd([ parser:pMany1(parser:pSat(fun (C1) -> not lists:member(C1, " ") end)), fun parser:pSpace/1, parser:pMany1(parser:pSat(fun (C1) -> not lists:member(C1, " ") end)), fun parser:pSpace/1, parser:pMany1(parser:pSat(fun (C1) -> not lists:member(C1, " ") end)), fun parser:pSpace/1, parser:pChar($[), parser:pMany1(parser:pSat(fun (C1) -> not lists:member(C1, "]") end)), parser:pChar($]), fun parser:pSpace/1, parser:pChar($") ]), String), {Str3, Str4} = parser:parse(parser:pAnd([ parser:pMany1(parser:pSat(fun (C1) -> not lists:member(C1, "\"") end)) ]), Str2), % io:format("~s~n", [Str3]), bench(N - 1).
※oregexp動いたで追記しています.
oregexpを試そうとしたけど,make test で失敗してしまう.
ソースを追う気力がないのでまた今度かなぁ.
rd@dev2:~/src/oregexp-1.2> make test
/usr/local/bin/erl -pa oregexp-1.2/ebin test -s run_tests run
Erlang (BEAM) emulator version 5.5.4 [source] [async-threads:0] [hipe] [kernel-poll:false]
{"init terminating in do_boot",{undef,[{eunit,run,[[test_basic,test_compare,test_options],{prefix,"test_"}]},{run_tests,run,0},{init,start_it,1},{init,start_em,1}]}}
Crash dump was written to: erl_crash.dump
init terminating in do_boot ()
make: *** [test] エラー 1
方法 | 言語 | 時間(sec) |
---|---|---|
文字列はString | Erlang (beam) | 0.312705 |
Erlang (native) | 0.118335 | |
Erlang (beam+smp) | 0.235028 | |
Erlang (native+smp) | 0.142893 | |
文字列はBinary | Erlang (beam) | 0.458387 |
Erlang (native) | 0.388640 | |
Erlang (beam+smp) | 0.415061 | |
Erlang (native+smp) | 0.343201 | |
配列にpushしてjoin | Perl | 0.741943 |
.=でつなげる | Perl | 0.538587 |
方法 | 言語 | 時間(sec) |
---|---|---|
iconv | Erlang (beam) | 0.604394 |
Erlang (native) | 0.612490 | |
Erlang (beam+smp) | 1.232886 | |
Erlang (native+smp) | 1.250170 | |
Unicode::Japanese | Perl | 0.646837 |
Encode | Perl | 1.403991 |
my $uj = new Unicode::Japanese; my $t0 = [gettimeofday]; for(my $i = 0; $i < 0xffff; $i++) { $uj->set("123あいう")->sjis; }
my $str = "123あいう"; for(my $i = 0; $i < 0xffff; $i++) { my $str2 = $str; Encode::from_to($str2, "UTF-8", "Shift_JIS"); }
方法 | 言語 | 時間(sec) |
---|---|---|
regexp | Erlang (beam) | 2.841569 |
Erlang (native) | 3.163096 | |
Erlang (beam+smp) | 2.474175 | |
Erlang (native+smp) | 2.693628 | |
正規表現 | Perl | 0.012415 |
bench() -> {ok, Reg1} = regexp:parse( "^[^ ]+ [^ ]+ [^ ]+ \\[[^\\]]+\\] \""), {ok, Reg2} = regexp:parse( "^[^ ]+ [^ ]+ [^ ]+ \\[[^\\]]+\\] \"([^\"]+)\""), String = "12.34.123.12 - - [17/Apr/2007:23:53:13 +0900] \"GET /html/123.html HTTP/1.1\" 200 6980 \"http://ayaya.jp/html/123.html\" \"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\"\n", Time = timer:tc(strregexp2, bench, [16#fff, Reg1, Reg2, String]), io:format("~w~n", [Time]). bench(0, _Reg1, _Reg2, _String) -> 0; bench(N, Reg1, Reg2, String) -> {match, _Start1, Len1} = regexp:match(String, Reg1), {match, _Start2, Len2} = regexp:match(String, Reg2), Match = string:substr(String, Len1 + 1, Len2 - Len1 - 1), bench(N - 1, Reg1, Reg2, String).
最近Erlangを勉強中なのだけど,かなり良い感触.
メジャーじゃない言語(C/C++,Perl,Java,PHP,Rubyくらい?)は,興味を持っても,実際に業務で導入する,というところまでは行かないのだけど,Erlangは実際に使いたいと思うほど.
MLでErlangの話の資料が公開されていて,
Threads is evil.
Processes are ugly.
State machines send you mad.
ということで,Erlang良いよ,という内容.
多数のリクエストを扱うようなサーバアプリケーションを作る場合,スレッドは見つけにくいバグがよく起こる上にそこまでスケールしないし,マルチプロセスは遅い&スケールしない.
C10K問題と言われていて,解決する方法としては,ノンブロッキング呼び出しとか非同期呼び出しで自前で各コネクションの状態を管理してがんばるしかないわけだけど,これは実装がかなり大変.
確かにパフォーマンスは最大限出るけれど,作るのが大変なので,普通のWebサービスに使ったりとかは難しい.
その点,Erlangなら,複数プロセスで処理をする場合と同じようにコードを書くだけで,C10K問題をクリアできる.
実際に,Erlangで書かれたサーバ(yaws)とApacheの対決結果などを見ても,8万以上のコネクションでも問題なく動作.
マイナー言語の宿命か,ドキュメントが貧弱だったり,ライブラリがもう少しほしい感じはするけど,オンメモリDB,ディスクDB(耐障害性は無し),分散DBは標準で付いてくる.ついPerlのCPANと比べてしまうけど(^^;,そういう比較をしなければそれなりに用意はされている感じ.
(ただしマルチバイト処理が欠けてるのは残念…)
Erlangのメリットとして,かなり並列処理でスケールしてくれる以外にも,クラッシュダンプの取得・解析が標準装備だったり,実行中のプロセスの状態を外部から確認できたり,動作したままコードを差し替えたり,ちゃんとプロファイラとかカバレッジが標準で付いていたり,業務で運用する場合に便利な機能がいっぱい.
どちらかというと,言語そのものというより,Erlang VM の環境が素敵.なのかな.
Erlang + Yaws vs. Ruby on Railsなんて記事もあるようで,Webアプリ作成にも向いていそう.
日本で使うなら,文字コード周りの面倒とかみないといけないし,自前で色々用意しないとだめそうだけど(^^;
もう少し日本で流行らないかなぁ...
ぐぐっても利用者少ない(^^;
jQuery history plugin - Ajaxアプリで戻るボタンを押したときに、操作前の状態に戻すためのjQueryプラグイン
にて紹介いただきました.ありがとうございます.
この動作は、イベント発生時に履歴にURLを追加しておいて、戻るボタンが押されたときは、ブラウザのキャッシュを利用して操作前の状態に戻すという感じでしょうか?
動作原理ですが,
1.location.hashを書き換えて戻るボタンの履歴に残るようにする
2.iframeのopen/closeで履歴に残るようにする
の2つをブラウザによって使い分けることで実現しています.
上記をすると,#以降の部分を変更させたものを履歴に残すことができます.
戻るボタンを押すと,#以降が以前の状態に戻るので,#以降の部分が変化していないか定期的にチェックすることで戻ったことを判定しています.
Ajaxと戻るボタン・ブックマーク
に参考にしたリンクがあります.
というわけで,
うーん。URLに画面の状態を持っておくとうまくいくのだろうか。。。
その通りで,#以降の部分に画面の状態を持たせておいて,必要に応じて#以降の部分から画面の状態を復元できるように作る必要があります.
Recent Comments