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


2014-10 最初のエントリ & 生存報告.

メモ

IMGP1635

(写真は以前に走ったときのもの)

行ってきます.はいそうですぼっちです.

しまなみ海道を走るのは 4年以上ぶり 2回目,自転車で走る関連のイベントは鈴鹿サーキットを走る以外では 2年半前に開通前の新東名高速道路を少し走った 以来 2回目でしょうか.まじイベント素人ですが楽しみです.

開催は 2014-10-26 ですが,受付が前日なので,明日土曜日朝のうちに出発する感じ.

せっかくなのでこれを持って行こうかしらw

新デザインでてるしw

関連エントリ

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


メモ

※ 「drop イベント云々」というよりは「DataTransfer#files が」という方が正しいですかね.

Dropzone.js を用いた,ローカルファイルをブラウザにドロップすることによるファイルアップロード機能の実装を試していて,Firefox と Chrome とで,その挙動の時間にあまりに差があったので,ちょっと確認.

気になる個所

Dropzone.js のソースコードを読んでたりした結果,Dropzone#drop での e.transferData.files の部分が怪しいのではないかということに.

ごく簡単な確認

drop イベントハンドラ内で DragEvent#transferData.files を呼び出す前後の時刻差を計算してみる.これが,ドロップするファイル数に対してどのように変化するのか.

マシン

  • MacBook Pro 15-inch, Late 2011
  • プロセッサ 2.5 GHz Intel Core i7
  • メモリ 16 GB 1333 MHz DDR3
  • ソフトウェア OS X 10.9.4(13E28)

古い.

ブラウザ

  • Firefox 32
  • Chrome 37

準備したファイル

  • 2500 点の JPEG ファイル
  • 5.5GB (2.25MB / ファイル)

コード

まっさらから準備するのがメンドウだったので,実装中のアプリケーションに対して,Dropzone#drop を上書きして上記の処理を行うだけにするなどして環境を準備:

class DZX extends Dropzone
    drop: (ev) ->
        [t1, t2] = [(new Date()).getTime(), null]
 
        files = ev.dataTransfer.files   # (A)
 
        t2 = (new Date()).getTime()
        result = (t2 - t1) / 1000
        console.log result
 
class DZModel
    dz: null
    constructor: (args) ->
        {target} = args
        dz_opts =
            url:                   'foobar'
            createImageThumbnails: false
            autoProcessQueue:      false
            autoQueue:             false
        @dz = new DZX(target, dz_opts)
 
window.onload = () ->
    new DZModel(target: '#dzmodel')

この状態でリロードしてはファイルをドロップしては...を繰り返す原始的な方法.特定のファイル数につき一度ずつしか計測していません.

結果

グラフについて,横軸がファイル数,縦軸が処理前後の「時刻差」(単位は「秒」).

A

ss-1410892971

Chrome は常にほぼ 0 なのにたいして,Firefox ではファイル数の増加に伴い指数関数的に処理時間が増加しているように伺える.

B

意味があるのかどうかわからないけど,先のコードの (A) の部分を「代入しない」形にしてみる.

        ev.dataTransfer.files   # (B)
ss-1410893217

A の場合と変わりはないみたい.

C

Event#dataTransfer にだけアクセスしてみた場合:

        ev.dataTransfer   # (C)
ss-1410894391

Firefox,Chrome 両者ファイル数に関係なくほぼ 0.

TSV データ

上記 A 〜 C の TSV データ:

まとめ

Firefox では,DataTransfer#files の参照処理時間が,ファイル数に対して指数関数的に増大する傾向にあるのではないか,という気がする.

実装するアップロード機能,最低 5000 ファイルくらいのドロップには対応できるようにしたいところだけど,Dropzone.js の問題でもなさげだしどうしたものかなぁ...

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


取り急ぎ発表資料を上げておきます.ご興味のある方は.

ちなみに壇上からの様子.

写真 2014-08-30 16 53 55

最終日キーノート発表の前枠なので,人がすごい.写真では見きれてますが,2階席からも見られているのでマジヤバイ.

発表で使用した MacBookAir,「ロジックボードの交換」のために「ピックアップ&デリバリー」による修理を依頼,20日に集荷でしたが,25日には戻ってきてくれました.バッテリまで交換されて.とにかく間に合ってよかったです.

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


メモ

こんな感じで書いていた String::Incremental ですが,本日,この人生初めての CPAN モジュールとしてリリースしてしまいました:

minil release の後の Enter を叩くのにかなりの勇気を要したことはおいておいて,まぁこんな感じで使ってみてください:

use strict;
use warnings;
use utf8;
use String::Incremental qw( incremental_string );
use Encode;
 
my $age = incremental_string( '0x%2=', [0..9, 'a'..'f'] );
$age->set( '0x24' );
 
$age++;
 
my $msg = sprintf( 'そして本日,%s 歳と相成りました.', $age );
print encode_utf8( $msg );

より詳細は上記リンクや Pod にて.

このモジュールで,私以外の 1人くらいの何かしらの助けになれば幸いでございます.そしてツッコミやパッチもお待ちしております.

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


はじめに

以前にこんなエントリを書きました:

Amon2 Web アプリケーションのコントローラ内とかで Data::Section::Simple::get_data_section を呼んで DATA セクションの内容を取得するようなコードを書いたのですが,ここでも,上記のような問題が発生してしまいます.

ので,その修正がてら,一対策方法としてメモしておきます.

サンプルコード

以下の内容は,このコードを基にしています.

事前準備

amon2-setup.pl --flabor=Minimum MyApp として.

サーバを起動しておきます:

carton exec -- perl script/myapp-server 2>/dev/null

アプリケーションに対してそこそこ並行して HTTP リクエストを投げるための簡単なスクリプト sandbox/req.pl:

use 5.18.0;
use warnings;
use utf8;
use Getopt::Long qw( :config posix_default no_ignore_case bundling );
use Time::HiRes ();
use HTTP::Tiny;
 
my %opts = (
    n => 10,
);
GetOptions(
    'n=i' => \$opts{n},
);
 
my $ua = HTTP::Tiny->new();
 
sub main {
    my (%args) = @_;
 
    my $pid0 = $$;
 
    for my $i ( 1 .. $args{n} ) {
        my $pid = fork();
        last if ! $pid;
    }
 
    if ( $$ == $pid0 ) {
        sleep 1;
    }
    else {
        Time::HiRes::sleep ( rand() / 100 );
        my $res = $ua->get( 'http://localhost:5000/' );
        say $res->{status};
    }
}
 
main( %opts );

問題のアプリケーション (branch master

リクエストが来たら DATA セクションを呼見込んでみて,OK なら 200,ダメなら 500 を返す,それだけです:

package MyApp::Web;
use strict;
use warnings;
use utf8;
use parent qw(MyApp Amon2::Web);
use File::Spec;
use Data::Section::Simple qw( get_data_section );
 
sub dispatch {
    my ($c) = @_;
 
    my $foo = get_data_section( 'foo' );
    my $res = $c->create_response( defined $foo ? 200 : 500 );
    $res->content_type( 'text/plain' );
    $res->content( defined $foo ? 'OK' : 'NG' );
 
    return $res;
}
 
1;
__DATA__
 
@@ foo
foobar

このアプリケーションに対して上記のスクリプトを使ってリクエストを投げてみます:

% for i in {1..10}; do echo "**** $i ****"; perl sandbox/req.pl -n 100 | grep 500; done
**** 1 ****
500
500
**** 2 ****
500
**** 3 ****
500
500
500
500
**** 4 ****
500
**** 5 ****
500
500
500
**** 6 ****
500
500
500
500
500
500
**** 7 ****
500
**** 8 ****
500
500
500
500
500
500
500
**** 9 ****
500
500
500
500
500
**** 10 ****
500
500
500

DATA セクションを読み込めていないことがあることがわかります.

とりあえず解決策 (branch solution

こんな考えを基に:

  • コンテキストクラスロード時に,各クラスの DATA セクションをまとめて読み込む
  • コンテキストオブジェクト経由で保持しているデータにアクセスできるようにする
  • あと,できれば,既存のコードをあまり変更したくない

変更内容はこんな感じ:

% g diff lib/MyApp/Web.pm
diff --git a/lib/MyApp/Web.pm b/lib/MyApp/Web.pm
index cd379ef..277192a 100644
--- a/lib/MyApp/Web.pm
+++ b/lib/MyApp/Web.pm
@@ -4,12 +4,35 @@ use warnings;
 use utf8;
 use parent qw(MyApp Amon2::Web);
 use File::Spec;
-use Data::Section::Simple qw( get_data_section );
+use Amon2::Util ();
+use Module::Find;
+use Data::Section::Simple ();
+
+__PACKAGE__->load_data_section();
+
+sub load_data_section {
+    my ($self) = @_;
+    my %data;
+    my @modules = ( __PACKAGE__, useall __PACKAGE__ );
+    for my $m ( @modules ) {
+        my $ds = Data::Section::Simple->new( $m );
+        $data{$m} = $ds->get_data_section();
+    }
+    Amon2::Util::add_method( __PACKAGE__, '__data__', sub { \%data } );
+}
+
+sub get_data_section {
+    my ($self, $key, $pkg) = @_;
+    $pkg ||= caller 0;
+    my $ret;
+    $ret = $self->__data__->{$pkg}{$key}  if $self->can( '__data__' );
+    return $ret;
+}
 
 sub dispatch {
     my ($c) = @_;
 
-    my $foo = get_data_section( 'foo' );
+    my $foo = $c->get_data_section( 'foo' );
     my $res = $c->create_response( defined $foo ? 200 : 500 );
     $res->content_type( 'text/plain' );
     $res->content( defined $foo ? 'OK' : 'NG' );

この変更で,アプリケーションの各所で get_data_section(...) していた部分は,$c->get_data_section(...) と変更するだけでよくなりました.

で,変更後のアプリケーションに対して同リクエストスクリプトを投げてみた結果:

% for i in {1..10}; do echo "**** $i ****"; perl sandbox/req.pl -n 10000 | grep 500; done
**** 1 ****
**** 2 ****
**** 3 ****
**** 4 ****
**** 5 ****
**** 6 ****
**** 7 ****
**** 8 ****
**** 9 ****
**** 10 ****

ちゃんと DATA セクションの内容を取得できているようです.(厳密には直接読み込んでいるわけではありませんが.)

おわりに

本エントリでサンプルとしてあげたのは Minimum flavor ですが,私が実際に修正したアプリケーションは Large flavor,同様の変更で対応できているようです.

1 of 12012345...102030...120