D-7 <altijd in beweging>

Day to day life of a Perl/Go/C/C++/whatever hacker. May include anything from tech, food, and family.

2009年11月

091129_1852~01.jpg
筋子の醤油漬けを作りたくて作りたくてしょうがなかったので、近くのスーパーへ。だが、ない。もう一つのスーパーへ。だが、ない。しょうがないのでとうとう渋谷まで出て、東急プラザ下の渋谷市場へ。うらあ、と2000円の筋子を購入。

魚焼きの網でイクラを分離。その後何回も薄皮とかをとりつつ洗う洗う。付属の出汁も入れたが、それ以外にも自前の煮きりを作って追加。一晩置いておいて、本日の夕飯に。今日アメ横にいったんだけど、これがあるから寿司とか食わずに我慢してきたかいがあった。

かけてもかけてもまだイクラがある幸せ。むほー。ごはんも進むぜ。イクラだけだとあれなので、昼頃に買ってきたぶつ切りの刺身を漬けにしたものも一緒に。ああ、いくらをいくらたべてもなくらない・・・幸せ・・・。
    このエントリーをはてなブックマークに追加 mixiチェック

思い立ったので適当に書いてみる
Perlのシグナルハンドラは%SIGグローバル変数にシグナル毎のハンドラを設定することで実現できる。例えばCtrl-CはSIGINTを発生させるので、INT用のハンドラを設定する:
$SIG{ INT } = sub { warn "got SIGINT!" };
%SIGに限った事ではないのだけれども、ここでまず注意しなくてはいけないのが、%SIGはグローバル変数であること。ある関数foo()内で%SIGをいじったあとにreturnすると、foo()を呼び出したスコープでもその値は有効になってしまう。これだと自分はよくても他のモジュール等に影響を与える可能性がある。そこでまず癖としてlocal修飾子を使う癖をつけてほしい
local $SIG{INT} = sub { warn "got SIGINT (OUTSIDE)" }; sub foo { warn "inside foo()"; local $SIG{INT} = sub { warn "got SIGINT (INSIDE foo)" }; sleep 10; } warn "sleeping..."; sleep 10; foo(); warn "outside foo()"; sleep 10;
こんなコードを書いて、foo()を呼ぶ前、foo()の中、foo()を呼んだ後、と3回Ctrl-Cを押すとハンドラの効果がfoo()内で局所化されているのがわかると思う(ちなみにsleep中にCtrl-Cするとsleepが邪魔されるので10秒待つことはなくなる)

ちなみに、この局所化はfork()した時にも是非同じ処理をするようにする癖をつけたほうがいい。fork()するような場合では親プロセスでSIGCHLD用の処理を入れてたりするのだが、それをうっかりそのまま継承するとopen("|-")系のコマンドをうっかり使ってしまった時などに問題が起こることがある。ちなみに、この場合は%SIG全体を局所化すればいいだろう:
my $pid = fork(); if (! defined $pid) { die "Could not fork: $!"; } if ( $pid ) { # 親プロセス } else { local %SIG; # これだけでOK ..... exit 1; }
シグナルはどの言語でもそうだけれども、普通のプログラム処理の流れをぶったぎって処理が入るものなので(厳密にはPerlの1OP毎にシグナルのチェックがはいるので、OP中にシグナルが入ることは基本的にはない)、とにかくシグナルハンドラ内で時間を食う処理をしない、に限る。

基本はフラグをたてるだけでさっとハンドラを終わらせるのが吉。例えばCtrl-Cした時に メインループを終わらせるなら、こんな感じ:
my $loop = 1; local $SIG{INT} = sub { $loop = 0; }; while ( $loop ) { .... }
自分がやりたいタイミングより1回余計にループが走るかもしれないけれど、逆にそこは基本の動作に任せてきれいにループを終えるほうが後々頭痛の種を作らない。さらに確実に停止したい動作に関してもうまくフラグをチェックしたりなんだりでやる方法が大概ある。

それでもやっぱりある程度の処理をシグナルハンドラ内でしなければいけない場合は、まずまっさきにハンドラ内でシグナルを無視するようにしたほうが良い:
local $SIG{ INT } = sub { local $SIG{ INT } = 'IGNORE'; # このハンドラ内ではSIGINTは無視 .... }

こうしないとSIGINTで受け付けた処理中にもう一度同じ処理が入ってしまうような妙な状態になってしまうことがる。

ただし、この方法はひとつだけ危険な問題があって、もし万が一ハンドラ内でブロックするような処理をしてしまった場合にはもうシグナルを無視しているのでCtrl-C等が効かなくなる。そういう意味でもやはりシグナルハンドラからは最小限の処理をしてとっととコントロールを元の状態に戻すのがおすすめ。開発当初はIGNOREをつけるのはおすすめしない。俺は何回もそれで失敗してる

ちなみに綺麗に全ての子プロセスを待つためのSIGCHLDなんかは結構面倒くさい。AnyEvent->child() ウォッチャーはその辺りがとても美しいので、便利ですね。ただしfork()の直後に子プロセスが失敗すると、運が悪いとハンドラー設定の前にSIGCHLDが発生してしまうことがあるらしいので注意。
    このエントリーをはてなブックマークに追加 mixiチェック

今のところJPA的な活動で個人的に一番手応えを感じているのが地方行脚活動なんだけど、関西系と九州系以外でPerlな人たちっていないのかしら。なんか東北とか、北海道はpmグループが存在しないくさいんだけど・・・

もしいるなら少人数でも行きたいのでご連絡をっ。

ちなみに近いうちにまた関西にでもいくかなぁ。特に最新のトピック、を話すより現実的な悩み相談レベルの話をさせてもらえる機会が欲しいと思っております。なにかあったら声をかけてください!
    このエントリーをはてなブックマークに追加 mixiチェック

# 追記: 2010 19 Feb - このコード何回も書くの面倒くさくなったので、
# CPANにモジュールアップロードしてしまいました
# http://search.cpan.org/dist/AnyEvent-FIFO/

まぁ考えてみれば単純な話ですけど、いわゆるGuardを使うとよいです。参考はAnyEvent::HTTP

コールバック$cbの最初の引数をguard変数にしておき、キューの1スロットを使用している間はこのguard変数をundefしないようにしておく感じです。
   use strict;
   use AnyEvent;
   use AnyEvent::Util;

   my @q; # 実際にコールバックを入れておくところ
   my $ACTIVE = 0; # 現在の使用中スロット
   my $MAX_ACTIVE = 1; # 最大何個のコールバックを「同時」に行うか(もちろん本当に同時じゃないよ!)

  sub drain_queue {
      while ( @q && $ACTIVE < $MAX_ACTIVE ) {
          if (my $cb = shift @q) {
              $ACTIVE++;
              $cb->( AnyEvent::Util::guard {
                  $ACTIVE--;
                  drain_queue();
              });
          }
      }
  }
デモ程度に 1から10までの数字を(最低)0.5秒あけてから表示するコード:
my $cv = AE::cv;

# XXX - 12/1: よくよく考えたらここはbegin()/end()使うところだったので
# 修正しておいた
for my $x (1..10) {
    $cv->begin;
    push @q, sub {
        my $guard = shift;
        my $w; $w = AE::timer 0.5, 0, sub {
            undef $guard;
            undef $w;
            warn $x;
            $cv->end;
        };
    };
}

drain_queue();

$cv->recv;
これ以外の実装の仕方もあるんだけれども、これだと次のqueue popとかを自前で呼ぶ必要がないのが素敵です。
    このエントリーをはてなブックマークに追加 mixiチェック

西原理恵子さんの漫画が大好きでほぼ全部所有してるくらいなのですが、彼女の漫画で心に残っている言葉のひとつに「人生に気合いの入っている人と麻雀を打ってはいけない」というのがあります。

麻雀歴はまだ浅い自分ではありますが、この言葉は結構守ってきたつもりです。細く長く麻雀を楽しみたいので財布が空になるまでとか、給料返上とかそういうことはしたくないのです。

で、まぁ漫画の中では歌舞伎町でエロ用具を○十年扱っている業者の社長とか、風俗街の内装を一手に引き受けているおっちゃんとかがでてくるんですが、今回好奇心に駆られ、渋谷で水商売を営んで20年のいきつけのバーのマスターN氏とそこのバーテンダーK氏、あといつも打っているO氏で卓を囲んでしまったのです。麻雀歴でいうと多分 N氏 > O氏 > 俺 > K氏 なのではないかと思いますが、とにかくN氏は伝説が多いのでどこまで本当かわかりません。これは打ってみないといけないな、と思い続けて何ヶ月、ついに日曜の夕方からの水商売の人のオフ時間に合わせて開催という運びになりました。

さて、最初の半荘、いきなり東2 で4000点台になるN氏「すわ、これは伝説だけが一人歩きしたパターンか?」と思ったのも束の間、「ここで巻き返す」と宣言した通り、いきなり親の跳ね満あがり。

その後も振り込んだり振り込まなかったりはあったものの、全体の勝負としては*全く*歯が立たなかった。

自分は一回だけ親の四暗刻で役満上がりを見せたものの、ほとんど2位か3位。K氏に至っては7半荘でプラスは一回だけという有様。とにかく役をそろえるという意味でも、逃げ切るという意味でも「あがる」タイミングがうますぎる。

というわけで役満ご祝儀のおかげでなんとか+69だったものの、+252のN氏には全く歯が立たなかった我々でした。何回か死ぬかと思った。

いつかへこましてやる><


    このエントリーをはてなブックマークに追加 mixiチェック

前のエントリではまともな事を書いたので、こっちは懇親会および帰京日のお散歩などについて。

というわけで初福岡です。九州は宮崎にしか行ったことなかったのですっかり宮崎のイメージでしたが、実際行ってみたら福岡すげいね。こりゃあ大都会だわー。普段旅行とかだと敢えて大都市は避けてるのもあって普通に驚いた。

空港からJR博多駅まで地下鉄で二駅とか近すぎる。何この便利さ。博多駅からホテルに徒歩で向かうも、いきなり逆方向に歩き出し、30分のロス。すでに飛行機が遅れてて、ホテルでスライド書こうと思ってたのに時間がいきなりなくなる。ギリギリまでスライドを書いて、地下鉄に乗って移動。駅を降りてまた反対方向に歩き出すも、今回は5分くらいで気づく。なんとか会場のヌーラボさんに到着。

懇親会のもつ鍋は大変大変おいしうございました。多分今週中にお取り寄せやります。1万円以上買うと送料無料とか言ってたけど、1万円分もモツ食えねぇよ・・・。誰か共同購入します?

懇親会の後、2次会でバーへ。一言だけ言わせてもらうと「ヌーラボのひとすげぇ!」

カラオケに誘われるも、後述の博多市内散歩したかったのでオールナイトの予感がしたカラオケに連れて行かれる前に脱兎のごとく逃走。ごめんなさいごめんなさい。次回行くときはもう観光しなくていいんで、カラオケ行きます。カラオケ好きです。

ホテルに戻り、ビールを飲みながらチャンネル数を数える。宮崎人の相方の「裏」「表」の話を聞いてからすっかりチャンネル数確認が習慣になってしまった。チャンネルはたくさんあった。さすが都会。

翌日6時起床。7時にホテルの飯を食べ、8時にチェックアウト。博多駅で荷物をコインロッカーに預け、移動開始。寒い!この日の天気と同じ九州だということに限って言うなら日南海岸が恋しい。言ってもしょうがないんだが。

とにかく西に歩く。知らない街はとりあえず歩きたい。時折自分の位置を確認しながら、いつのまにか福岡城跡に到着。そこから引き返す形で天神を通って昨晩もいた中州到着。結構バブリーなショッピングセンター、イニミニマニモで肉を食う。

アーケード商店街を通り、櫛田神社へ。七五三の真っ最中。子供はかわいいが、写真を撮りまくる親は正直ちょっと邪魔・・・。でっかい山笠がかざられてた。天保年間の灯籠とか鳥居とかにしばし萌えた後、同じ商店街を戻って地下鉄。

博多駅で土産。また荷物を取って、また地下鉄で今度は福岡空港。また土産。どんだけ買うんじゃ。で、帰宅。夕飯に近所のインド料理屋でほうれん草のカレーがうますぎてテンションあがったまま就寝。

ちなみに時期的にそうなだけかもしれませんが、博多は女性のタイツ率が高くて眼福でした。

博多は楽しかったのでまた近いうちに是非いきたいと思います。
杉山さん、山本さん、鰺坂さん、Fukuoka.pmの皆様、大変お世話になりました。林さん、次回はつきあいます。
また呼んでくださいねー。
    このエントリーをはてなブックマークに追加 mixiチェック

11/14、ようやく杉山さんとの去年?からの約束を果たすべく福岡に行って、Fukuoka Perl Workshop #14 に参加してきました。

都内でやっているイベントでは比較的最先端技術とかを話す人が多いですが、地方にいくと必ずと言っていいほど「実務的な話」のリクエストがあがります。今回もご多分に漏れずまっさきにそういうリクエストが出たので、JPAの肩書きで参加はしたものの、弊社endeworksの実例を出して色々どういう開発手法を採っているのかを話させていただきました。


発表の時はJPAのロゴが入ったスライドだったんですが、内容がJPA公式とかじゃなくてendeworksの物なので味気ない真っ白背景に修正しました。内容はあくまでendeworksの話ですよ!!


その後の懇親会ももつ鍋をいただきながら地元の雇用・仕事事情をたくさん聞く事ができました。やはり地方だとお役所の方針とかもあってPerl以外の言語を強要されることも多いそうで、なかなか弊社みたいに全面的にPerlで開発をするチャンスには恵まれないとの事。でも正直もっとチャンスさえあればぐいぐいPerlの事をやってくれそうな予感がする、良い技術者の人たちにたくさん会えた気がします。

こういう言い方はちょっと失礼かもしれないけれども、これだけのパワーがあるなら関東でPerlの仕事に恵まれている弊社のような会社はもっと地方に仕事をオフショアするべきなんじゃないのかなぁ、と夢想しております。せっかくネットリテラシーがあるんだから遠隔作業をもっとうまくやれるべきだよねぇ・・・。まぁまだまだ夢想の段階ですが、なにかうまくやれたらと思います。

さて、JPAで各地のPerlイベントに顔を出すというのもやっと2回目ですが、もし他の地方でイベントがある際は是非呼んでください!どこへでもいきます!

    このエントリーをはてなブックマークに追加 mixiチェック

Morris君の中身を書き換えてAnyEvent::DBIにしてみたわけだが、一個だけはまった部分があったので、メモっておく。

例えば以下のようなコードをAnyEvent::DBIを使うように変更したいとする。
use strict; use DBI; my $dbh = DBI->connect('dbi:SQLite:dbname=test.db'); $dbh->do( "CREATE TABLE IF NOT EXIST t1 (c1 int not null, c2 int not null)"); $dbh->do( "DELETE FROM t1"); for my $i (0..10) { $dbh->do( "INSERT INTO t1 (c1, c2) VALUES (?, ?)", $i, $i * 2); } my $sth = $dbh->prepare("SELECT * FROM t1"); # まぁ本当ならbind_columns使うけど while ( my $row = $sth->fetchrow_arrayref ) ) { print "c1 = $row->[0], c2 = $row->[1]\n"; }
これをまずさくっと以下のようにすると動かない
use strict; use AnyEvent::DBI; my $dbh = AnyEvent::DBI->new( "dbi:SQLite:dbname=test.db", undef, undef, undef, exec_server => 1, ); $dbh->exec( "CREATE TABLE IF NOT EXIST t1 (c1 int not null, c2 int not null)"); $dbh->exec( "DELETE FROM t1"); for my $i (0..10) { $dbh->exec( "INSERT INTO t1 (c1, c2) VALUES (?, ?)", $i, $i * 2); } my $cv = AnyEvent->condvar; $dbh->exec("SELECT * FROM t1", sub { my ($dbh, $rows, $rv) = @_; foreach my $row (@$rows) { print "c1 = $row->[0], c2 = $row->[1]\n"; } $cv->send; }); $cv->recv;

理由はシンプル。exec()の最後の引数としてコールバックを指定していないから。もちろん、本来であれば一個一個戻り値とかを確認すべきなんだけど、とりあえず動かしたい場合とかあるじゃない。そういう場合に結構はまりがちなので、ここは何もしない空のコールバックを用意する
use strict; use AnyEvent::DBI; my $noop = sub {}; my $dbh = AnyEvent::DBI->new( "dbi:SQLite:dbname=test.db", undef, undef, undef, exec_server => 1, ); $dbh->exec( "CREATE TABLE IF NOT EXIST t1 (c1 int not null, c2 int not null)", $noop); $dbh->exec( "DELETE FROM t1", $noop); for my $i (0..10) { $dbh->exec( "INSERT INTO t1 (c1, c2) VALUES (?, ?)", $i, $i * 2, $noop); } my $cv = AnyEvent->condvar; $dbh->exec("SELECT * FROM t1", sub { my ($dbh, $rows, $rv) = @_; foreach my $row (@$rows) { print "c1 = $row->[0], c2 = $row->[1]\n"; } $cv->send; }); $cv->recv;
ちょっぴり面倒くさいね!
    このエントリーをはてなブックマークに追加 mixiチェック

Morris君をAnyEvent::DBI対応にしてみました。これでデータベースアクセスも非同期になったのであります。

やー、よくできたライブラリ群だなぁ。変更は簡単でした。POEの時大変だったから、実にうれしい。
    このエントリーをはてなブックマークに追加 mixiチェック

恒例の歩き。環七から淡島通り、そこから駒場東大駅を抜けて代々木上原のあたり。久しぶりに来たのでパン屋とかみたり。井の頭通りから代々木公園を突っ切って原宿へいき、明治神宮。右に折れて千駄ヶ谷駅到着。

皆さんがフリマをやっているはずだったのでチラ見しながら一度通り抜け、信濃町へ。メーヤウという店でカレー。うまいけど激辛。汗だく。また行きたい。辛すぎて疲れたのでプロントでお茶。明治公園に戻り、みんなの顔を見て、千駄ヶ谷駅へ。


電車に乗ると道中短いくせに乗り換えが多いので、ハチ公バスに乗る。快適快適。一気に渋谷到着。フードショウで金目鯛の干物を買って、帰宅後昼寝。金目鯛は夕飯。うまし。

あ、そういえば道中どこかで船越英一郎さんの家らしきものを見ました。車に「KAZUYO」って書いてあった。あと、代々木上原でその晩ケータイ大喜利に出てた高山善廣さんを見かけた・・・と思う。
    このエントリーをはてなブックマークに追加 mixiチェック

キャベツと豚バラ肉とトマトとコンソメを用意します。キャベツはたっぷり用意。適度な大きさ(手のひらサイズ)とかに切ります。トマトは適当に。肉は軽く塩しておきます。キャベツ、肉、トマト、という順番でラザニアのようにそれぞれの具の層を鍋に敷き詰めます。かさは減るから適当に加減すること。

ふたをして弱火で温めます。弱火ですよ!水とかはいれません。そのうち水気は自動的に出てきます。

その間にコンソメを軽く水に溶いておきます。量は適当だけど、僕は鍋一杯作る時に一個いれますな。

水気が出てきたらあんまりびちゃびちゃにしない程度にそのコンソメをいれていきます。なので水に溶くときにはあんまりたっぷりの水にはいれないように。

火が通ったら、食べる直前に多めのオリーブオイルをぶわーっといれます。あついうちにどうぞ。

まぁ、巻いてないロールキャベツだよね、これ。
    このエントリーをはてなブックマークに追加 mixiチェック

この間はまったのでメモ
package MyObject; use Moose; use overload # overloadの色々... ; use namespace::clean;
これだと、overload.pmが適用してくれる関数も削除してしまうので、オーバーロードが効かない。なので、overloadを適用するMooseオブジェクトはこうやって書かないといけない:
package MyObject; use Moose; use overload ....; no Moose;
それだけ。
    このエントリーをはてなブックマークに追加 mixiチェック


Moose + POEなIRCボット作ろうと前に思い立って、結構長いこと弊社内で使ってたんですが、このたびAnyEvent化して色々モダナイズしました。やっぱり非同期なhttp_getしてる部分とかは抜群に速いなぁ。

AnyEvent したついでにAnyEvent::MPにも対応したですよ。POE::IKCと違って、一旦セットアップしちゃえば、Morrisの外から何かをポストするのにコマンドラインから一発でできる;
aemp morris privmsg "#channel" "Your comment"
ただMPってセットアップが結構面倒くさいのね。以下はまったり考え込んだりしてしまったところ:

  • 最初動かない時になにやってんんだかわからないので、PERL_ANYEVENT_MP_TRACEとPERL_ANYEVENT_MP_WARNLEVELを設定したほうがいい。後者は10くらいにしないとなんも有用な事を言ってくれない。
  • seedの役割をするプロセスが必要。Morris自身がseedになれないかなーと思ってやってみたけど、トレースで「refuses to talks to myself」みたいなこと言われた。
  • .perl-anyevent-mpファイルに受け側のbind情報を書いておいたほうがデバッグは楽かも。実際に動かす段階ではどのポートでも使えるようにしたほうが簡単かもしれない。
  • rcv/sndとportの使い方、シンタックスエラーにならない限り間違った使い方をしていてもなんの注意もしてくれないので、よくわかってない間はAnyEvent::MPディストリビューションの eg/内を見たほうがいいかもしれない。
  • MPやAnyEvent::IRCのようなネットワーク接続型のAnyEventモジュールを使っていると環境によっては"Out of memory!"エラーが出てくる事がある。もしバックエンドを特に指定しないでAnyEventを動かしている場合は、素直にEV.pmをアップグレードしてみるとよい。なぜか直る。
以上。Morris君は結構お気に入りなのであった。
    このエントリーをはてなブックマークに追加 mixiチェック

三軒茶屋から茶沢通りを北上する形で開始。下北沢の喧噪を迂回しながら東北沢、大山あたりをなめて、笹塚へ。ついでに幡ヶ谷。ここまでで1時間半。予想以上に近すぎるので、さらに北上して中野に行くことに。

甲州街道を越えて、裏道をうろうろ。オリンパス工場とかなめつつ、住宅街。中野通に合流。夜にテレビで見たけど、ビフォーアフターに出てた店の横を通ってたらしい。全く気がつかなかった。

中野には12時40分くらいに到着。三軒茶屋を出発したのが10時すぎくらいなので、まぁ3時間かからずというところか。まっすぐ行けば2時間?わからんけど。


中野ブロードウェイ初体験。まんだらけで「征地球論」(愛蔵版のほう)を購入。半分くらいすでに読んだことがあったが、日に焼けた本の状態が俺のもってる「緑の守り神」と酷似しててついつい。

飯でも食っても帰るべか、ということで表通りを抜け、横道に。中華料理屋さんいっぱい。ふと見ると、これもやさまに出てたビルじゃん!と気づき、ちょっと見に行く。俺の散歩はもやさまの真似じゃないんだ、もう前からずっとこういう散歩してるんだよ、俺はっ!と世間様に言いたい衝動に駆られつつ、適当な店に入る。豚キムチ定食。うまし。

帰りはバスで渋谷まで。NHK前にいた抗議のヤジがひどくて萎えた。自分がすっきりしたいだけならもっと静かにしていただきたい。

夕飯は普通の乾麺の棊子麺。うまし。
    このエントリーをはてなブックマークに追加 mixiチェック

このページのトップヘ