« April 2007 | Main | June 2007 »

Thursday, May 31, 2007

OperaはComet+JSONP出来ない

IEとCometの相性が悪いで書いた問題を回避するため,複数ドメインを使うことにした.
まぁ,この問題の他にも,同一ドメインには同時2本しか接続がはれないので,そのドメインで同時に1つしか閲覧されないという前提が無い限りは,複数ドメインにしておいた方が良いと言うこともあった.

複数ドメインに分けると,クロスドメインの制約があるためにAjaxが使えなくなる.
そこで,JSONPを使うわけだけども,ここでまた問題が...

OperaでJSONP+Cometすると,Cometの応答が返ってくるまで,すべてのJavaScriptが止まってしまう.
どうやら,scriptタグでスクリプトを読み込んでいる間は,JavaScriptの実行が止まってしまう模様.
仕方なく,Operaの場合はAjaxを使うようにして回避...

また,scriptタグを付け足す方式なので,エラーチェックが出来ないのも難点.
Ajaxではサーバとの接続が切れれば,すぐにエラーが返ってくるのに,
scriptタグの場合はタイムアウトを待つしかない.
この辺も不便.

うーん,結局AjaxでCometするにしても,JSONP+Cometするにしても色々めんどくさい.

チャットとかやりたい場合は,Flash+XMLSocketを使って通信して,
Flash / JavaScript Integration kitとか使ってJavaScript側に制御を渡すのが楽そう?

詳しくは見ていないけど,チャベリというサイトが
Flash+XMLSocket+JavaScriptでやっているぽい.


| | Comments (3) | TrackBack (0)

Monday, May 28, 2007

ErlangからPerl正規表現

Erlang+Perl (組み込みドライバ編) #2より


関数呼び出しをどうにかとばすーってことで, がんばってみました. 直接正規表現生成&実行

というわけで新しいバージョンができたので,早速テスト.

SMP無しbeamで,0.92秒,SMP有りnativeで,0.83秒くらい.
oregexpより1割程度速くなった♪すばらし.

正規表現としてはPerlの方がなれているので,これを使っていこう.

| | Comments (0) | TrackBack (0)

Thursday, May 24, 2007

ErlangからPerlを使う

ErlangからPerlを使うより

ただ、今のところは、RBridgeにせよErlang::Portにせよ、粗結合型のbridgeなので、作りやすく使いやすい一方、密結合--組み込み型もちょっと欲しくなってくる。

これはむしろErlang⇔Perlの通信に絡むoverheadの方が大きいと思う。粗結合型の一番の欠点がこれ。小さなタスクだと、サーバー側(RBridgeではerlang, Erlang::Port では perl)の処理よりも通信コストの方が高い。これを何とかしたいところなのだけど....

もちろん,密結合の組み込み型でも試してもらってある.
「限界までチューン」してもらうところで,Perlを別プロセスではなくライブラリで呼び出す形への埋め込み,通信内容をバイナリにしたり,Erlang側のコードの最適化,Perl側のコードのXS化などあらゆる手を尽くしてもらった・・・と思う.
それでも,残念ながら十分に速くならなかった.

Perl側で正規表現を実行するためには,Erlang側から2つの文字列を渡し,関数を1回呼び出し,その結果を戻す必要がある.
この2つの文字列を渡して関数を呼び出して戻す,というだけでかなり時間がかかってしまう.

Perlは,正規表現を直接使うI/FがXSレベルで用意されていないようなので,これ以上の改善は無理そう.
(さすがにPerlのソースを切り貼りしてやるのは死ぬほど大変そうなので)

oregexpは,正規表現ライブラリの鬼車を使うものだけど,正規表現をコンパイルした結果をキャッシュして使うことが可能で,これを使うと非常に速かった.

正規表現のエンジン自体はPerlの方がずっと良いと思うのだけど,密結合させても呼び出し時のオーバーヘッドが大きすぎてダメだった.
正規表現のループだけなら,0.2秒なのに,呼び出しオーバーヘッドで1.2秒ほどかかるような状況なので...

% 詳しくは氷魚にゃがブログに書いてくれると思う.たぶん.

今度は逆に、Perl側からErlangを呼び出すモジュールも欲しい。このあたりが参考になる。

これは何に使うのでしょう?
Perl側からErlangを呼び出せてもうれしくなさそうなものだけども...

ErlangはVM環境とセットになっているので,起動・終了のオーバーヘッドが大きいので,Erlangを内部で使ってもあまりうれしくない気がする.
1回起動して,そのインスタンスと通信を行うような形にすると,Perl側がメッセージを受け取るためにイベントループみたいなのを用意しないといけないし,使い勝手が悪いように思う...

相互で通信したいのであれば,Perl側を Erlang の C Node のような形にして,Erlang Node と対等に通信させるのが一番じゃないかと思うのだけど,どうでしょう.
まぁ,これでも使うのは結構めんどくさそうだけども...

Interoperability Tutorial - C Node

| | Comments (0) | TrackBack (0)

oregexp動いた

以前にoregexp動かない…と書いたが,その後動くようになった.

動かないと思っていたのは,テストコードだけだった模様.
eunitという別のモジュールが必要だったらしい.
eunitを見つけて入れてみたけど,やっぱりなんかうまくいかない.
(めんどくさいので深追いはしていない…)

とりあえずoregexp自体は正常に動作するのを確認できた.
こんな感じで利用できる.

1> oregexp_svr:start().
{ok,<0.33.0>}
2> oregexp:match("http://www.mikage.to/test.html", "([\\w\\.]+)").
{match,1,4,[{0,"http"},{1,"http"}]}
3> oregexp:match("http://www.mikage.to/test.html", "\/\/([\\w\\.]+)").
{match,6,15,[{0,"//www.mikage.to"},{1,"www.mikage.to"}]}

ベンチを取ってみると,かなり速い.
parseしてからmatchする方法であれば,parserを使う方法と同等以上の速度.

smp無しbeamで0.977秒くらいの速度が出た.

氷魚にゃさんにErlangからPerlを呼び出すモジュールを作ってもらい,限界までチューンしたけど,それより速い.
Perlの方は,関数呼び出しを1回挟まないとダメで,それが大きなオーバーヘッドになってしまっている模様.

oregexpベンチのソースは以下のような感じ.

-module(strregexpo).
-export([bench/0, bench/2]).

bench() ->
oregexp_svr:start(),
{ok, Reg} = oregexp:parse("^[^ ]+ [^ ]+ [^ ]+ \\[[^\\]]+\\] \"([^\"]+)\""),
Time = timer:tc(strregexpo, bench, [16#ffff, Reg]),
io:format("~w~n", [Time]).

bench(0, _Reg) ->
0;
bench(N, Reg) ->
String = "12.34.123.12 - - [17/Apr/2007:23:53:13 +0900] \"GET /html/1495.html HTTP/1.1\" 200 6980 \"http:/
/wiki.ffo.jp/html/2633.html\" \"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\"\n",
oregexp:match(String, Reg),
bench(N - 1, Reg).

Erlangで文字列操作をするときは,oregexpが正解っぽい.

| | Comments (0) | TrackBack (2)

Wednesday, May 16, 2007

IEとCometの相性が悪い

IEでチャットにログインして,リロードしたりすると,反応が無くなる,という問題があるようで,調べてみた.

Firefoxの場合,Ajaxでサーバに接続中にリロードすると,その接続は切断される.
リロードした以上,そのページで発行したAjaxリクエストは処理を続行する必要がないと思うので,切断するのが普通なのではないかと思うのだけども,IEはそうではない模様.

IEの場合,リロードしても接続したコネクションが張りっぱなしになってしまう.
1ホストに対して同時2コネクションの制限はその状態でも有効なため,追加のAjaxリクエストが待たされて,投稿が出来なかったり,応答が無かったりするということのよう.

今のチャットだと,入室後に新規発言を待っている時は,Cometコネクションが1本.
そこでリロードすると,ページを表示し直すため,もう1回Cometコネクションが追加で張られる.
入室ボタンを押すと,別のAjaxリクエストで入室フォームをpostするのだけど,既に2本接続を張っているので,そのpostが遅延されてしまう.
うーん・・・

Lingrはどうやってるのかなーと思って調べてみたら,リロードするたびにComet先のホスト名が変わるようになっていた.
こういう回避策しかないのかな?
DNS周りもいじらないといけないから結構めんどくさそうだ.JSONPに変えたりもしないとだめそうだし...
色々罠が多い.(^^;

というわけでこの問題を直すのには少々時間がかかりそう.

| | Comments (0) | TrackBack (0)

Friday, May 11, 2007

Erlangのデータ保存方法の速度比較

Erlangでは,データを保存する方法が色々あるので,速度を比較してみた.
チャットのログを保存することを想定して,process dictionary,ets,dets で比較.

チャットのログを1000行として,以下の方法で1000回実行させた時間を比較.

・pd: process dictionary(ログの永続化無し)
・pd_dets: process dictionary + 書き込み時に dets にも保存
・ets: ets(ログの永続化無し).named_table を使用して都度読み書き.
・dets: dets.最初に開いてそのテーブルを使い続ける.都度読み書き.
・dets_local: dets.テーブルを毎回開いて読んで書いて閉じる.

SMP無し,nativeコンパイルで,以下のような感じ.

pd: size 1000 time {4759,true}
pd_dets: size 1000 time {1816660,true}
ets: size 1000 time {1143908,true}
dets: size 1000 time {4363103,true}
dets_local: size 1000 time {12769167,true}
※単位はマイクロ秒

process dictionary が最も速い.
マニュアル的には,あまり使わない方が・・・みたいな記述があった気がするけど(グローバル変数相当だし?),速度を気にする場合は重要な感じ.

ちなみに,ベンチは単にループさせているだけで,処理を行うのは1プロセス.
こういう場合にsmpオプションを使うと,オーバーヘッドだけかかってかえって遅くなってしまう模様.

ソース:chatbench.erl

| | Comments (0) | TrackBack (0)

Wednesday, May 09, 2007

Erlangは関数型だけど難しくない

Erlangで簡単なアプリまで書けるくらいになったので,感想を.

関数型言語というと,Lisp,Haskellなどがあって,どれも難しいイメージ.
Erlangもはじめは結構覚えるの大変かなぁという印象があった.

Lispは括弧だらけでまず見た目から拒否反応が起こる.
HaskellはふつうのHaskellとか読んでみたけど,遅延評価やモナドがやはり難しいイメージ.
今までのように,書いた順番に実行されるという点が違ったり,デバッグするときに好きなときにprint入れたり出来ないのは,やっぱりかなり影響が大きい.
※追記:unsafePerformIOって関数で無理矢理printさせたりできるらしい.危険らしいけど(^^;

その点,Erlangはそういう難しさが全くなかった.
書いた順番に普通に実行されるし,副作用がどうとか気にする必要も無し.
エラー時は(見にくいけど)スタックトレースが普通に出るし,デバッグにprint入れるのも普通に出来る.

言語仕様自体もシンプルで,覚えるのが思ったよりも簡単だった.
ただ,言語自体がシンプルなために,結構必須に近いような操作でも全部モジュールになっていて,どのモジュールにどの機能があるかを把握しておかないと,うまくコードを書けない.
ここが一番大変だったところかなぁ.

そのほか,グローバル変数が無いというものの,Erlangプロセス内でグローバルな process dictionaly があるのでグローバル変数代わりに使えたりとか,プロセス間のデータはメッセージパッシングで,というものの,ets・dets・mnesiaなどを使えばプロセス間でデータを共有できるし,プロセス間でmutexのような排他制御を行うこともできる.
言語自体はこういう方向で,というのはあるものの,それ以外の書き方も幅広く許容しているように感じた.
こういう色々なやり方が出来るところは,Perlとちょっとにているかも?


結構Erlangが密かなブームになっている気はするものの,期待しすぎているような話も結構あるように思う.

Erlangのプロセスはスレッドよりずっと軽量だけど,言語自体全体が軽量なわけではなくて,やっぱり動的な型を採用しているだけあって,静的な型の言語には速度で負ける.
マルチコア時代に適しているといっても,ベースの速度が違うので,単に高速に処理させたい目的で使うのには向かない.
ネットワーク系のアプリケーションとか,並列処理が必要な分野に限って,I/O多重化などの面倒な手法を使わずとも,十分高速な性能を確保できる,という程度のものだと思う.
(わたしとしてはここが一番うれしくて,非常に大きなメリットなわけだけども.(^^;)

SMPサポートはErlangの歴史の中ではつい最近サポートされたもので,まだspawnとかドライバ処理などが十分スケールしないようだし.ベンチを取ってみると,条件によってはSMPサポートを有効にすると,より遅くなってしまうケースも.

あとは,HiPEというネイティブコンパイラもついているけど,これもあまり期待できない.
速くなるものもあるけど,ものによっては逆に遅くなったり.

Erlangのメリットは,ネットワークアプリケーションなど並列処理が必要なものや,複数マシンでの分散処理が必要なものに限られそう.
Perlとかなら,それ以外の分野(文字列処理とか様々な雑用処理とか)でも便利に使えるけど,Erlangはそうではないので,なかなか趣味でやる人はあまりいない気がする.
業務で使う・・・となると,やっぱり実際にやろうとする人は減ってしまうのかなぁ.

ともかく,もう少し広まるとうれしいけど...

| | Comments (0) | TrackBack (1)

Monday, May 07, 2007

jQueryでKeep-Aliveされない問題

ErlangでCometのサンプルを利用されている方から,Connection: close になっているよ,との指摘をいただいた.
で,早速調べてみると,IE・FirefoxではKeep-Aliveだが,Firefoxではcloseになってしまう.
ブラウザ側がリクエストするときに,Connection: close をつけているので,サーバ側の問題ではないようだ.

jQueryのソースを見てみると,

// Make sure the browser sends the right content length
if ( xml.overrideMimeType )
xml.setRequestHeader("Connection", "close");

というコードがあった.

ぐぐってみると,prototype.jsでも同様の処理がある模様.

/* Force "Connection: close" for Mozilla browsers to work around
* a bug where XMLHttpReqeuest sends an incorrect Content-length
* header. See Mozilla Bugzilla #246651.
*/
if (this.transport.overrideMimeType)
requestHeaders.push('Connection', 'close');

とあるので,必要な対策っぽい.

ただ,該当バグは
Bug 246651 – XMLHttpRequest doesn't calculate Content-Length correctly
でもうcloseされているので,1年前には直っている模様.

Keep-Aliveが使えないと,Firewallの負荷などをあげてしまいそうだけど,どっちをとるかだなぁ.
古いブラウザは知らないよ,と言えるなら,Keep-Aliveにできそうだ.
ただ,prototype.jsもjQuery.jsもこの対策をとっているということは,そういうユーザも少なからずいる,ってことなんだろうなぁ.うーむ.

| | Comments (0) | TrackBack (0)

Thursday, May 03, 2007

Programming Erlang 日本語訳

Programming Erlang を訳してみている(via Programming Erlang が訳されている模様)で Programming Erlang を翻訳されている方がいる模様.

英語苦手なわたしとしては,英語で読むとどうしても理解度が減ってしまうので,今後に期待.
周りにも英語苦手な人が多いけど,日本語訳があればだいぶ覚えやすくなりそうだし.
協力は出来ませんが勝手に期待しています.(^^;

| | Comments (0) | TrackBack (0)

Wednesday, May 02, 2007

Erlangメモ.ets・yaws

Erlangで適当にサンプルコードを書いて練習中.
寄り道しながら作っているせいか,なかなか進まない.

その中でのメモ.

・yawsの中でetsを使いたい場合,yaws起動時にetsテーブルを作成する必要があるが,
 その場合は yaws.conf の ebin_dir の中にモジュールを置き,runmod = モジュール名,
 の指定を追加する.
 そうすると,yaws起動時にモジュールの start/0 が呼ばれるので,その中で
 etsテーブルの作成などを行う.

・etsテーブルは作成した後,作成したプロセスが消滅すると存在も消える.
 これはpublicにしていても同様.
 yawsのダイナミックコンテンツの中で使いたい場合は,以下のように
 適当なループをつけてプロセスを生存させておく.

start() ->
	ets:new(chatlog, [public, named_table]),
	ets:insert(chatlog, {log, []}),
	ets:insert(chatlog, {logid, 0}),
	loop().

loop() ->
receive
_ -> true
end,
loop().

・etsテーブルは,named_table指定をしておけば,他のプロセスから
 名前でそのままアクセスできるので便利.
 (多少のオーバーヘッドはありそう)

・yawsの yaws_api:parse_post() などで返るデータは,{key, value} 形式のタプルだが,
 keyはString型.マニュアルではatomとなっているが,たぶん問題があってやめたのだろう.
 (外部からいろんなキーを送りつけられると,Erlang VM 内のatom数の上限に当たって
  VMが止まる(?)とかの問題を起こしそう.
  マニュアル読んでいてまずくないのかなー?と思ったら,実際のコードの動きが違った.)

・yaws_api:parse_post() などで返るデータは,lists:key~ の関数を使うと便利に処理できる.

・ets:update_counter はあらかじめ指定する Key のデータを作っておかないといけない.

・yaws -i -T で起動するとシェルが使え,通信内容も全部見れるので便利.
 io:format() のデバッグ出力なども表示されるので開発しやすい.
 ets:tab2list(テーブル名) とかで内容を確認しながらデバッグ.

| | Comments (0) | TrackBack (1)

« April 2007 | Main | June 2007 »