時計を壊せ

駆け出してからそこそこ経ったWebプログラマーの雑記

Cartonで不要になったモジュールをcpanfile.snapshotから削除したい

こうすることで消せた:

rm -rf local
carton install --deployment
carton install

なんか良い方法ないかなー。

追記: 2015-06-11 17:03

CIでcpanfile.snapshotを生成すれば解決しそう

参考: www.songmu.jp

YAPC::Asia Tokyo 2014で個人スポンサーしつつボランティアスタッフしつつperl5 meta programmingについて喋りつつreject conでWorkmanについてLTしました

タイトルが長い。

YAPC::Asiaとは

ここを読むと良い。

概要 / ABOUT - YAPC::Asia Tokyo 2014

Perlのトーク殆ど無いじゃんという意見についての個人的な見解

いまどき色々な言語が開発に利用されるのは当たり前だし、特定の言語だけに絞るメリットはあまり無いのではって思う。
Perlを使ってい(る|た)人が興味が深い他言語/他分野の話をしてもPerlの人には面白いし役立つしべつに良いじゃないか。楽しみ方はいくらでもある。

YAPC::Asiaと私、あるいは何故ぼくは個人スポンサーになったか

YAPC::Asiaは2011年から毎年参加しているが、質が高く素晴らしいイベントであり、良いコミュニティになっていると思う。
僕は毎年ここで開発への情熱を貰っている。色々な技術に触れてわくわくする。エンジニアとしての将来のキャリアに希望が持てる。色々な人に来てもらいたい。
そういう素晴らしいイベントも、継続するためにはやはりお金が必要だと思う。個人で出来る事は少ないけれど、少しでも運営の助けになればと思い、小額ではあるが個人スポンサーをさせて頂いた。

ボランティアスタッフをやった

2012年から個人スポンサーはやらせて頂いていたが、今年からJPAYAPC運営委員会がYAPCの主催を行うということになり、 運営リーダーも牧さんから和田さんに変わるなど、新体制での運営となった。
いろいろ大変なこともあるかもしれないので少しでも力になれればと思い、コアスタッフとしてお手伝いすることも考えたが、 ボランティアスタッフすら経験していないのに勝手が分かるはずが無いと思い、まずはボランティアスタッフとしてお手伝いしていこうと思ったので参加を決めた。

作業としてはコアスタッフの人々が殆どの事を決めてくれていたので、殆ど手を動かすだけで済んだ。
具体的には、特典のTシャツを畳んだり、マイクを質問者のもとに届けたり、懇親会の参加者への案内をしたり、イベントホール外で飲食が無いよう*1grepしてblockしにかかる仕事とかをしていた。

今年はひたすらスタッフをやってみようと思っていたので、トークは殆ど聞かなかった。*2
ぼくは短大の頃に文化祭の主催をするなどしていたので、懐かしい気分になれた。一部でもYAPC::Asiaをつくることに貢献できることに喜びがあった。
終われば懇親会やHUBでいろんなひとと飲んで騒いでできたし、keynote sessionのときは仕事は全部終わっていたので生で見た。楽しかった。

トークについて

Perl5 meta programming - YAPC::Asia Tokyo 2014ということで、Perl5でメタプログラミングをするための基礎的な要素について初学者向けに実際のコードを交えつつ解説した。(スライドはリンク先に掲載している) UNIVERSALとAUTOLOADは隣り合わせにするつもりだったがスライドを整理しているうちにズレてしまっていたなど、いろいろ不手際はあったが、少しでもpure perlメタプログラミングをするための方法について伝われば幸いである。 本当はもう少し実践的な話もしたかったが、これは別の機会でも良いだろう。 なお、このトークのスケジュールはPerl入学式Githubの裏側の話Perlあるある、そして あやかNowという人気トークの裏にあったので、当日はそんなに人は来ないだろうと目論んでおり、非常に気を抜いてリラックスして発表していたが、最終的には立ち見で聴いて頂く方も出てくるなど思いのほか多くの人に来て頂き本当に有難い限りだった。ありがとうございました。 毎年YAPCに来るたびに英語力の無さを実感していたので、英語力を鍛える意味を込めつつ英語でスライドを書いたが、もう一つ海外ゲストの人との話のネタにしたいという思いもあった。しかし、案の定というかGithubの裏側の話に吸い込まれたようでそれは叶わなかった。来年までにはもうちょっと喋れるくらいの英語力とコミュ力を身に付けたい。

LTについて

reject conでLTをした。

karupanerura/Workman · GitHub

これのデモをひたすらやった感じ。酔っ払ってたのでだいぶテキトーだった。 デモをやる裏で動画をひたすら流していて最高にカオスだった。 自分でやっておいて自分で吹き出してしまってしょうもない感じだった。

WORKMAN_CM - YouTube

YAPC Ramen Challenge

きました。

やりました。

f:id:karupanerura:20140904202906j:plain

dump sql type name. · b57ce92 · karupanerura/p5-Teng · GitHub

総括

めっちゃ楽しかったし継続していきたいので来年も(ボランティア)?スタッフやりつつ参加したいです! 関係者の皆様おつかれさまでした!ありがとうございました!来年もやりましょう!(手伝います!

*1:諸事情でイベントホール以外では飲食の許可が得られていなかった

*2:良い同僚が代わりに聞いて、社内でフィードバック会を開いてくれる事になっていたので、それを聞きつつスライドやYoutubeで補完すればいいやとなった。

Job-Queue Workerの実装を管理するdaemon

Message Queueとか

だいたいみんな、Message QueueとしてGearmanとかQ4MとかResqueとかRabbitMQとかZeroMQとかまあたくさんあるけど、なにかを使っていると思う。 Perlの人だとQudoとかTheSchwartzとかをつかっている人も多いと思う。
でも、preforkなworkerを実装するとなるとSignal処理とかをちゃんとやるのが意外と難しい。 下の2つのスライドを読むと難しいんだなぁという事がなんとなくわかるとおもう。

graceful shutdownとかgraceful restartとかは欲しいし、max_reqs_per_child的なこともしたいし、時間が掛かり過ぎているjobはリトライして新しいworkerで処理させたいとかそういう要求がある。
そこで、そのへんが共通化されたプロダクトがあると良いのではないかと考えた。

Dainamoについて

なお、perlにおいては似ている既成のプロジェクトとしてDainamoというものがある。*1

これは以下のような事ができて、以下のようなメリットがある。

  • Message Queueの種類をあまり考慮せずにコードが書ける
  • サーバー毎にworker数を設定し、Profileという単位でweightをかけてworker数をバランスする
    • サーバー毎のプロセス数をスペックに合わせて管理しやすい
    • Profileを1つのプロジェクトで複数つくって即処理したいものはweightを多めにするといったこともできる
  • 設定ファイルからProfile::Group(Profileをまとめたもの)を複数読み込み、全てのworkerを起動できる
    • 複数プロジェクトが同居するケースとかのセットアップが楽

これは業務で運用しているが、とても便利な反面、困ったこともいくつかでてきた。

  • dainamo毎にworker数を設定し、Profileという単位でweightをかけてworker数をバランスする
    • 実際にProfileに割り当てられるプロセス数が分かりにくい。
    • 他のProfileの影響を受けてProfileのworker数が変化するので複数Projectの同居などを慎重に検討しなければならない。
  • graceful_shutdown_timeout(default:10秒)を超えるとSIGKILLをworkerプロセスに送る
    • 容赦が無さすぎて失敗時に走らせたい処理とかが出来ない
  • Proc::Daemonでdaemonizeする機能がある
  • 3段階のforkとなっていてデバッグし辛い
    • master process -> manager process (profile毎に1つ) -> worker process (実際のjobを捌く)
    • (依存モジュールが古いサーバーとかだと)manager processだけゾンビってるとかが稀にある

Workmanについて

というわけで、もっとシンプルなものが欲しいと思っていた。そこで最近、Workman というプロジェクトを開始した。 Job-Queue Worker frameworkと銘打っている。だいたい以下のような事が出来る事を目標にしている。

あらゆるMessage Queueを同一のインターフェースで扱う事が出来る

  • 時代の変化で古いMessage Queueから新しいMessage Queueに移行するときとかにあまりめんどくさい事考えたくない。
  • 代わりに、一部のMessage Queueに特有の機能は使いにくくなるがそれは許容する。
  • Queueバインディングの仕様を満たすためのテストを提供してQueueバインディングを開発しやすくする。

単一のProfileに対して単一のServerを立てる

  • (dainamoと比較して)manager process単位でサーバーを立てる。
  • 複数建てたければ建てればいい

上に挙げた2つのスライドのノウハウを取り入れる

  • シグナルハンドリングの不具合とかを心配したくない。

graceful shutdown / graceful shutdown をサポートする

  • 1つだけ時間がかかっているjobがあったとしても他のworkerはすぐrestartして欲しい
  • かといっていつまでも死なないのも困るのでgraceful_shutdown_timeoutを超えたら強制終了させる

graceful_shutdown_timeoutを過ぎて強制終了させるときにSIGABRTを送る

  • worker内ではWorkman::Server::Exception::ForceKilledがthrowされるのでそれを好きにゴニョる
  • on_abortというhookがあるので再enqueueなどの処理を書いてあげる

max_reqs_per_childしてくれる

  • あたりまえのようにサポートしてほしい

daemonizeをサポートしない

テストを充実させる

  • 特にシグナル処理の安全性やWorkerのライフサイクルとかは手動で動作確認とか結構厳しいし自動化するべきである

CodeRefを簡単にworkerにしたい

  • ちょっとしたプロジェクトとかだとあると便利なはず。Amon2::Lite的な発想。syntax sugar用意してもいいかも。
  • 当然classとしてもタスクを定義出来るようにする。

実装状況

実は、だいたいコア部分はできている。 たまにテストがコケる事はあるが、sleepとか絡むので仕方ないのかなともおもう。 以下のような感じで書くともうだいたい動く。

サーバー側

use strict;
use warnings;
use utf8;

use Data::Dumper;
use Workman::Server;
use Workman::Server::Profile;
use Workman::Queue::Gearman;
use Workman::Task;

my $queue   = Workman::Queue::Gearman->new(job_servers => ['127.0.0.1:7003']);
my $profile = Workman::Server::Profile->new(max_workers => 10, queue => $queue);
$profile->set_task_loader(sub {
    my $set = shift;

    warn "[$$] register tasks...";
    $set->add(
        Workman::Task->new(Echo => sub {
            my $args = shift;
            warn Dumper $args;
            return $args;
        })
    );
    $set->add(
        Workman::Task->new(Abort => sub {
            my $args = shift;
            die Dumper $args;
            return;
        })
    );
    $set->add(
        Workman::Task->new(Busy => sub {
            my $args = shift;
            sleep 1 for 1..1000;
            return;
        })
    );
});

Workman::Server->new(profile => $profile)->run();

set_task_loaderはWorkerプロセスで実行されるのがミソ。
この中でモジュールのロードを行えばgraceful restartしたときでもTaskが再読み込みできるし、 メモリを節約したいなら先に読んでおいてCoWを効かせてメモリを節約することもできる。 重いモジュールは先に読ませておくとかそういう小手先の諸々ができる。

クライアント側

use strict;
use warnings;
use utf8;

use Workman::Client;
use Workman::Queue::Gearman;
use Try::Tiny;
use Data::Dumper;

my $queue   = Workman::Queue::Gearman->new(job_servers => ['127.0.0.1:7003']);
my $client = Workman::Client->new(queue => $queue);

$client->enqueue_background(Echo => { msg => 'hello' }) for 1..10000;

こんなかんじで、共通化のインターフェースでenqueueできる。 ドキュメンテーションとか、configファイルから読む機能とか、簡単にworker serverを立ち上げるためのコマンドとかはこれからという段階だが、なんとなく雰囲気は伝わるかなと思う。 どうだろうか?

*1:gearman限定であればMasayuki Matsuki / Gearman-Starter - search.cpan.orgがある

Time::Strptime進捗

頭を悩ませながらのんびり作ってます。
https://github.com/karupanerura/Time-Strptime

Time::Strptimeとは

strptimeのpure perlによる実装です。
epochとoffsetだけを返すシンプルな機能を持っています。
pure perlですが最小構成のperl codeを文字列として構築してevalする事により条件分岐の回数などを極限まで減らし高速な動作を実現しています。

最近の変更

timezoneサポートを実装しました

具体的には%Z/%zを環境依存*1でparse出来るようになりました。
また、この変更に伴い、offsetを返すようになりました。parseした文字列のtimezone/offset、あるいは現在のtimezoneからoffsetを計算し、返します。
offsetの計算にはTime::TZOffsetが利用出きるケースではTime::TZOffsetを利用し、そうでないケースではTime::Localを利用しています。

localeサポートを実装しました

具体的には%b/%aがparse出来るようになりました。
Encode::LocaleとPOSIX::strftimeを使って動的に組み立てるというカッコイイことをしています。*2

ベンチマークスクリプトを更新しました

https://github.com/karupanerura/Time-Strptime/blob/master/author/benchmark.pl
Time::Pieceのインスタンスをキャッシュしてstrptimeするケースと、キャッシュしないケースを分けました。
テストも同時に実行しており、同じ結果を返すケースでのベンチマークである事がちゃんと分かるようになっています。
GMT/UTCにおいて、Time::Pieceのインスタンスをキャッシュしないケースより45%程度高速というベンチマーク結果となっております。


tpがTime::Piece、dtがDateTime、tsがTime::Strptime(本モジュール)です。

    # Subtest: GMT(+0000)
    ok 1
    ok 2
    1..2
ok 1 - GMT(+0000)
Benchmark: timing 100000 iterations of dt, dt(cached), tp, tp(cached), ts, ts(cached)...
        dt: 47 wallclock secs (46.43 usr +  0.09 sys = 46.52 CPU) @ 2149.61/s (n=100000)
dt(cached): 27 wallclock secs (27.22 usr +  0.05 sys = 27.27 CPU) @ 3667.03/s (n=100000)
        tp:  2 wallclock secs ( 1.62 usr +  0.00 sys =  1.62 CPU) @ 61728.40/s (n=100000)
tp(cached):  1 wallclock secs ( 0.96 usr +  0.01 sys =  0.97 CPU) @ 103092.78/s (n=100000)
        ts: 34 wallclock secs (34.09 usr +  0.11 sys = 34.20 CPU) @ 2923.98/s (n=100000)
ts(cached):  1 wallclock secs ( 1.12 usr +  0.00 sys =  1.12 CPU) @ 89285.71/s (n=100000)
               Rate       dt       ts dt(cached)        tp ts(cached) tp(cached)
dt           2150/s       --     -26%       -41%      -97%       -98%       -98%
ts           2924/s      36%       --       -20%      -95%       -97%       -97%
dt(cached)   3667/s      71%      25%         --      -94%       -96%       -96%
tp          61728/s    2772%    2011%      1583%        --       -31%       -40%
ts(cached)  89286/s    4054%    2954%      2335%       45%         --       -13%
tp(cached) 103093/s    4696%    3426%      2711%       67%        15%         --
    # Subtest: UTC(+0000)
    ok 1
    ok 2
    1..2
ok 2 - UTC(+0000)
Benchmark: timing 100000 iterations of dt, dt(cached), tp, tp(cached), ts, ts(cached)...
        dt: 47 wallclock secs (46.49 usr +  0.08 sys = 46.57 CPU) @ 2147.31/s (n=100000)
dt(cached): 27 wallclock secs (26.62 usr +  0.05 sys = 26.67 CPU) @ 3749.53/s (n=100000)
        tp:  1 wallclock secs ( 1.64 usr +  0.00 sys =  1.64 CPU) @ 60975.61/s (n=100000)
tp(cached):  1 wallclock secs ( 0.81 usr +  0.00 sys =  0.81 CPU) @ 123456.79/s (n=100000)
        ts: 34 wallclock secs (33.53 usr +  0.11 sys = 33.64 CPU) @ 2972.65/s (n=100000)
ts(cached):  1 wallclock secs ( 1.13 usr +  0.00 sys =  1.13 CPU) @ 88495.58/s (n=100000)
               Rate       dt       ts dt(cached)        tp ts(cached) tp(cached)
dt           2147/s       --     -28%       -43%      -96%       -98%       -98%
ts           2973/s      38%       --       -21%      -95%       -97%       -98%
dt(cached)   3750/s      75%      26%         --      -94%       -96%       -97%
tp          60976/s    2740%    1951%      1526%        --       -31%       -51%
ts(cached)  88496/s    4021%    2877%      2260%       45%         --       -28%
tp(cached) 123457/s    5649%    4053%      3193%      102%        40%         --
    # Subtest: Asia/Tokyo(+0900)
    ok 1
    ok 2
    1..2
ok 3 - Asia/Tokyo(+0900)
Benchmark: timing 100000 iterations of dt, dt(cached), tp, tp(cached), ts, ts(cached)...
        dt: 55 wallclock secs (54.70 usr +  0.11 sys = 54.81 CPU) @ 1824.48/s (n=100000)
dt(cached): 34 wallclock secs (33.92 usr +  0.06 sys = 33.98 CPU) @ 2942.91/s (n=100000)
        tp:  2 wallclock secs ( 1.61 usr +  0.01 sys =  1.62 CPU) @ 61728.40/s (n=100000)
tp(cached):  1 wallclock secs ( 0.79 usr +  0.00 sys =  0.79 CPU) @ 126582.28/s (n=100000)
        ts: 39 wallclock secs (39.50 usr +  0.13 sys = 39.63 CPU) @ 2523.34/s (n=100000)
ts(cached):  2 wallclock secs ( 1.79 usr +  0.01 sys =  1.80 CPU) @ 55555.56/s (n=100000)
               Rate       dt       ts dt(cached) ts(cached)        tp tp(cached)
dt           1824/s       --     -28%       -38%       -97%      -97%       -99%
ts           2523/s      38%       --       -14%       -95%      -96%       -98%
dt(cached)   2943/s      61%      17%         --       -95%      -95%       -98%
ts(cached)  55556/s    2945%    2102%      1788%         --      -10%       -56%
tp          61728/s    3283%    2346%      1998%        11%        --       -51%
tp(cached) 126582/s    6838%    4916%      4201%       128%      105%         --
    # Subtest: America/Whitehorse(-0700)
    ok 1
    ok 2
    1..2
ok 4 - America/Whitehorse(-0700)
Benchmark: timing 100000 iterations of dt, dt(cached), tp, tp(cached), ts, ts(cached)...
        dt: 57 wallclock secs (56.63 usr +  0.11 sys = 56.74 CPU) @ 1762.43/s (n=100000)
dt(cached): 36 wallclock secs (35.81 usr +  0.06 sys = 35.87 CPU) @ 2787.84/s (n=100000)
        tp:  2 wallclock secs ( 1.67 usr +  0.01 sys =  1.68 CPU) @ 59523.81/s (n=100000)
tp(cached):  1 wallclock secs ( 0.80 usr +  0.00 sys =  0.80 CPU) @ 125000.00/s (n=100000)
        ts: 40 wallclock secs (40.52 usr +  0.14 sys = 40.66 CPU) @ 2459.42/s (n=100000)
ts(cached):  3 wallclock secs ( 2.06 usr +  0.01 sys =  2.07 CPU) @ 48309.18/s (n=100000)
               Rate       dt       ts dt(cached) ts(cached)        tp tp(cached)
dt           1762/s       --     -28%       -37%       -96%      -97%       -99%
ts           2459/s      40%       --       -12%       -95%      -96%       -98%
dt(cached)   2788/s      58%      13%         --       -94%      -95%       -98%
ts(cached)  48309/s    2641%    1864%      1633%         --      -19%       -61%
tp          59524/s    3277%    2320%      2035%        23%        --       -52%
tp(cached) 125000/s    6992%    4982%      4384%       159%      110%         --
1..4

TODO

リファクタリング

スキマ時間でえいやと実装を進めてしまいがちで、カオスになってきたので整理する。

テストケースの追加

なんか微妙なバグを拾いきれてないきがするのでテストを整える。

サポートするべきフォーマットの選定/実装

他の実装のstrptimeを見てみて必要があらば実装する。

ドキュメンテーション

サポートしているformatの説明と形式、localeの変更のしかたなどを説明する。

リリース

https://github.com/chansen/p5-time-moment/issues/4#issuecomment-36947533
有益っぽいのではやくリリースしたい。

XSによる高速化

Time::Localの実行が遅いので互換制のあるインターフェースでXS版を書いてみる。

XS実装の作成

libcのstrptimeだと%z/%Zがparse出来ないので、結構頑張る必要がある。(たぶん作らない)

[追記] timezone処理の環境依存を切る

http://www.iana.org/time-zones のあたりからいい感じにモジュール化して別のpackageで出してそれに依存させる。

*1:/usr/share/localeなどに依存

*2:やめたい

state変数は初期化のタイミングで例外が発生しても二度と初期化が行われる事は無い

タイトルの通り。
まあ、初期化は1度しか行われないので、あたりまえといえばあたりまえですがハマったのでメモ。


以下検証コード。undef,2,2となるかと思いきや初期化は1度しか行われないのでundef,undef,undefとなる。

static variable be undef if throw when initialize ...

#yapcasia 2013の感想とParallel::Asyncを書いたはなし

前夜祭

前夜祭では昨年のLTソンと同じくらいの熱気が会場を沸かせ、ときにはApache::LogFormat::CompileとかNorikuraとか真面目なプロダクトの紹介もありつつ、Acme系のはなしなどいろいろあっておもしろかったです。
ぼくも熱気に当てられて飛び込みLTとかやりました。ネタのつもりだったけど滑って残念な感じですみませんでした。

なお、スライドでも触れてる通り、ポチポチゲーの印象がつよいソシャゲですが、
最近はパズドラなどゲームゲームしているものも多く、遊ぶのも開発するのも面白いものが多いですので、
この機会に遊んでみては如何でしょうか。
中で触れてる奴についてはごにょごにょしてる最中ですの気になる方はで続報をお待ち頂ければと思います。

1日目

自分の発表まで資料の見直しと圧縮やらを繰り返しつつトークを聴いていました。

@rjbs さんのトークはPerl5.18あたりで入った新機能や廃止されるかもしれない機能、Perl開発の実態についての紹介でした。ガンガンいい感じの機能いれてこうぜって感じのアツいトークだった気がします。英語勉強しようと思いました。


id:songmu さんのDBまわりのはなしは、(たぶん)同業種かつ同職種である故か、知ってるところはうんうんうんとすごい勢いで同意したり、しらなかったところは id:kfly8 と「これやろうぜ!!」って盛り上がったりしました。


トークが終わった頃には次に聞こうと思っていた id:myfinder さんのRiakのはなしは既に始まっていて、
会場に着いたころには結構話がすすんでしまっていたきがします。
ぼくはRiakについて殆ど知らなかったので、あとで調べて発表のYoutube聴き直しながら勉強しようとおもいました。


お昼は @python_spameggs さんと麺場ハマトラに行きました。熱々濃厚で美味しかったです。


午後は id:yappo さんのメンテナンスしやすいコードを保つためのtool chainの工夫みたいなところで、
現状のsetupスクリプトの課題と、その解決策としてKsgkを作ったという感じの話でした。
だいぶテンションあがりました。


このあとぼくの発表でした。

緊張しててカバン背負ったまま壇上に立ち、それに気付いて頭が真っ白になって、アレな感じでした。
詳細は http://karupanerura.hateblo.jp/entry/2013/09/21/164133 をどうぞ。
Youtube見なおしたらやっぱりだいぶ酷くで申し訳なさでいっぱいであります。。。
次こそはと思っているので、来年の運営には少しでも力になれればと思っております。


そのあとは気ままにトーク聴いたりBOF行ったりぶらぶらしてました。
id:ry_mizuki がSpicaという素晴らしいモジュール書いてたのでLTでいいから発表しようぜとpushしたら発表してくれました!


Clientライブラリが無い、BtoB向けのAPIやマイナーなサービスのAPIを叩くときとかに重宝すると思います。
万能ではないけどだいたいのケースに対応出来るのでいいかんじです。
CPANにあがるのを

懇親会は去年以上にいろいろな人とおはなし出来て楽しかったし、料理も酒も美味しくて素晴らしかったです!
懇親会スポンサーの:DeNAさんありがとうございました!

懇親会のあとはHubに行ってなんか呑みながらくっちゃべってたきがしますが気が抜けすぎて酔っ払ってあんまり覚えていません。


あと家帰っていろいろ考えて反省とかしてたきがする。

2日目


こんなかんじでした

Hackathon


日曜日は用事があり公式のHackathonには行けなかったので月曜日にひとりHackathonをやりました。
最近、仕事でJavaを書く機会があり、Javaはカジュアルに並列処理を書けるので、
Perlでもカジュアルに並列処理できたらおもしろそうだなと思ってつくりました。

こんなかんじで並列処理が書けます。waitとか考えてなさそうなかんじ、カジュアルです。

use Parallel::Async;

my $task1 = async {
    my $res = ...;
    return $res;
};
my $task2 = async {
    my $res = ...;
    return $res;
};
my $task3 = async {
    my $res = ...;
    return $res;
};

my ($res1, $res2, $res3) = $task1->join($task2)->join($task3)->recv();

単純にforkすることやdaemonizeする事もメソッド1つ呼び出せば出来るようなかんじになっております。
isucon予選では即興でのworker代わりに使おうとしましたが時間がありませんでした。*1
けっこういい感じだと思いますので良かったらお使いください。

最後に

素晴らしいイベントをいままで育て、主導して運営してきた id:lestrrat さん、 id:941 さん、スタッフのみなさん、ありがとうございました。
本文中にもちらっと書いておりますが、来年の開催、運営を微力でもお手伝いできればと考えております。
コード書く事くらいしか取り柄がありませんがお力添えできれば幸いです。

*1:本当はResqueとかq4mとか使ったほうがよいはず。去年は時間切れで活きませんでしたがCluntchを使いました。

#yapcasia 2013 で 「ぼくがかんがえたさいきょうのMVC」について話してきました

昨日の13:40から多目的教室3で「ぼくがかんがえたさいきょうのMVC」という題でトークをさせて頂きました。


http://yapcasia.org/2013/talk/show/f60b8522-d43e-11e2-ac80-4cc16aeab6a4

内容について

大それたタイトルですが、MVC disというかんじではなく、上手くMVCを使うためにそれぞれのアプリケーションの要件に最適化した「ぼくがかんがえたさいきょうのMVC」をつくり、そこに対して規約を作り運用していくとだいぶ良い感じですよという感じの話で話をさせて頂きました。
20分は思いの外短いなということで、トピックスに対する答えはだいたい詰め込んだつもりですが、
時間の都合上一部削ったものもあります。すみません。


前半でMVCを何故カスタマイズするべきかについて触れ、後半でMVCをカスタマイズする例*1とそれを守るためにチーム内規約を作って運用するのオススメですという感じの事を話しました。
MVCは抽象的、って表現はいま思えば適当ではなかったです。「MVCは必ずしもあなたの書こうとしているアプリケーションの構成要素に対して具体的な紐付けが確定されているものではない」って表現のがたぶん僕の言いたい事に近いです。
なので具体的な構成要素との紐付けは自分で考えなければいけないけど、チーム内で解釈にブレが出るとカオスになるし、ちょっとイレギュラーな事をやってるとどこに紐付ければ良いか分からなくなるので、具体的に目的のアプリケーションのどの部分とMVCそれぞれが紐づくのか具体化しましょうということが伝えたかったです。


今回、MVC自体がビギナー向けの話題ではないかもしれないと思い、レギュラー向けで応募させて頂きましたが、ビギナーの方にも分かりやすい内容にまとめられたかなと思います。スライドはぜひご覧ください。内容についておかしいと思う点、不明な点があれば、Twitterのメンションやコメント欄などでぜひ気軽に質問/反論してください。



という問題があったみたいで、Sub Room3で id:yappo さんのトークを聴いていたのですが、Sub Room2での発表だと思ってちょっと前に抜けてSub Room2に行ったら違かったので慌ててSub Room3に戻ってだいぶ緊張した状態でトークを始める感じになるというハプニングもありました。
※これは僕が事前にちゃんとトークの前後関係や部屋を把握していれば防げた問題で、僕の責任です。アプリ自体は非常に便利に利用させて頂きました。作者の方、本当にありがとうございます。

*1:実例をもとに簡略化しました