カテゴリおよびタグ一覧 アーカイブ

python-stdnet

この記事はPython Advent Calendar 2014の7日目です。引き続きRedisネタです。

python-stdnetはPython製のRedisオブジェクトマッパーの一つで、よくあるオブジェクトリレーショナルマッパー(ORM)のパターンに非常に似たものになっています。

機能

  1. モデルを定義します
  2. クエリでとってきます

なんか前回の記事とかわりませんね。

モデルの定義

このようにしてモデルを定義します。

from stdnet import odm


class User(odm.StdModel):
    email = odm.SymbolField(required=True, unique=True)
    salt = odm.CharField()
    hash = odm.CharField()
    created_at = odm.DateTimeField(default=time.time)

SymbolFieldとCharFieldはどちらも文字列を格納する目的ですが、SymbolFieldがインデックスされ、CharFieldはインデックスされません。

あんまり前回の記事とかわりませんね。

クエリなど

定義したものはこのように使えます。

models = orm.Router('redis://localhost?db=1')
models.register(User)
user = models.user.new(email='user@host.com')
user.salt, user.hash = gen_hash(password)
user.save()

user = models.user.get(email='user@host.com')
at_gmail = models.user.filter(email__endwith='@gmail.com').all()

ルーターに対してモデルを登録してクエリでとってくるやりかたです。

ほか

  • python-stdnetで定義していないモデルへの参照を可能にするModelField

どんなときに使えるのか

  • 基本的に前回の記事のromと同じユースケースです
  • RedisのCPUを比較的に多めに使う設計になっているのでRedisが暇そうならこちら

どうやって動いてるの

  • 基本的に前回の記事のromと同じです

どっち使えばいいのさ

  • Redis以外のバックエンドも検討するならpython-stdnet
  • プライマリキーを任意に設定したいならpython-stdnet
  • シンプルにマッピングしたいだけならrom
  • Djangoと連携をしたいならpython-stdnet

Djangoと連携?とは?

こんなのがあります

rom

この記事はPython Advent Calendar 2014の6日目です。

romはPython製のRedisオブジェクトマッパーの一つで、よくあるオブジェクトリレーショナルマッパー(ORM)のパターンに非常に似たものになっています。

機能

  1. モデルを定義します
  2. クエリでとってきます

なんかどこかでみたことありますね。

モデルの定義

このようにしてモデルを定義します。

import rom

# All models to be handled by rom must derived from rom.Model
class User(rom.Model):
    email = rom.String(required=True, unique=True, suffix=True)
    salt = rom.String()
    hash = rom.String()
    created_at = rom.Float(default=time.time)

なんかどこかでみたことありますね。

クエリなど

定義したものはこのように使えます。

user = User(email='user@host.com')
user.salt, user.hash = gen_hash(password)
user.save()

user = User.get_by(email='user@host.com')
at_gmail = User.query.endswith(email='@gmail.com').all()

なんかどこかでみたことありますね。

ほか

  • モデルごとにデータベースを設定できるマルチデータベース
  • romで定義していないモデルへのForeignKey参照フィールド

どんなときに使えるのか

  • Redisが使える開発環境であり(必須) 、リレーショナルデータベースだとレイテンシが気になるとき
  • Redis上で単純なデータ構造以上のものを表現したいとき
  • DjangoのORMっぽいものをRedisバックエンドで使いたいとき

どうやって動いてるの

  • モデルデータはプライマリキーをキーにしたHashに入っています
  • モデルデータを検索可能にするためにSetやSortedSetに射影しています

IE7でCORSを実現する

http://qiita.com/zaru/items/6e57ab83a8e0e40f2115

IE6,7は死亡(もういいよね)

よくないことが稀にある。 IE8, 9ではXDomainRequestを使うことでCORSを実現できる。ただしその方法はIE7では使えない。

IE7では要件としてFlashが有効であるブラウザに限定できるならeasyXDMが使える。

http://easyxdm.net/wp/

なぜFlashが必要なのかは http://easyxdm.net/wp/2011/04/13/microsoft-security-bulletin-ms11-018/

よくあるユースケースとしてはjQueryのajaxでCORSをしたいということがある。

https://github.com/GyldendalDigital/jQuery-EasyXDM

レガシーIEのデバッグ環境について

口上

モダンブラウザが普及した今日、いまだレガシーIEは死なず。 つまりそれはクロスブラウザ動作確認をIEでも行わなければならないことを意味する。

IEである。

レガシーIEの入手方法について

モダンな開発者であれば仮想マシンは常識であるのでmodern.IE( https://www.modern.ie/ja-jp/virtualization-tools )を使用する。各ホストOS向けにイメージが配布されているのでそれをダウンロードすればよい。

ただし中身はIEしか入っていないWindows環境なので後述する方法でデバッグ環境を構築する必要がある。さもなければ死ぬ。

デバッグ環境の構築について

Microsoft Script Editorかそれが同梱されているMicrosoft Officeを所持しているならばそれをインストールして使用する。 所持していなければVisual Studio Express( http://www.visualstudio.com/downloads/download-visual-studio-vs) をインストールする。for Webあたりでよい。 ここで注意が必要なのはVisual Studio Express 2013のシステム要件は Windows 7 以上となっており、modern.IEのIE7のOSである Windows Vista では動作しない。あきらめてページ下部にあるVisual Web Developer 2010 Expressをインストールする。 なおこのインストールは時間がかかるのでインストーラーを走らせてから他の作業を並行するとよい。

デバッグについて

ここまで整備すればあと一歩である。

  1. IEのInternet Options -> Advanced -> Disable script debugging (Internet Explorer)のチェックを外し、
  2. Visual Studio側でFile -> New Web Siteでプロジェクトを作成し、
  3. Debug -> Start Debuggingすればよい。

レガシーなデバッグ環境にはdeminifyなどというモダンな機能はついていないのでminifyしていないコードを使うことを推奨する。

超チューニング祭で努力賞(最速賞)をとるためにやったこと

3行で

  • ソーシャルハック(要件定義)
  • 計測

獲得品.jpg

はじめに

2日にわたる超チューニング祭 in ニコニコ超会議3最速になってきました。参加された方々、スタッフの方々にはお世話になりました。ありがとうございました。

1日目午前にやったこと

レギュレーションの確認

  • サーバ側にロジックはいれない
  • ページのソースコードは対象サーバへアップロードする
  • CSS, JSなどのアセットはCDNにのせていい
  • 運営側が計測
  • iPhone iOS 7.1.1 mobile safariベースの計測ツールをつかう
  • 指定されたいくつかの要素が表示されていること

sftp用の秘密鍵がDropbox経由で各自に配布され、10時くらいに開始。コードを落そうとsftpでつなぎにいくが、ポートが標準ではないようでつながらない。 コード落としつつレギュレーションを検討した。

  • サーバ側にロジックはいれない
  • gzは有効か
  • .htaccessでコントロールは可能か
  • ページのソースコードは対象サーバへアップロードする
  • sftpってことはsshでのりこめ。。。なかった
  • 運営側が計測
  • 計測回数はどれくらいか平均化できるか
  • 回線はどれを使うか LANか外部ネットワークか
    • docomo LTEを使うとの回答をえた
  • 指定されたいくつかの要素が表示されていること
  • 表示していればいいのか
    • 最低要件を満たすHTMLを検討したが、ユーザ投票で見た目が計測されるため却下

なにはともあれコードを動かす準備。

$ git init .
$ git add *
$ git commit -m init
$ python -m SimpleHTTPServer

深く考えずにHTTPサーバを立ちあげられるPythonは良い環境。

こういうときの調査はChromeのDeveloper Toolsで性質を調べる。

  • 明らかにjqueryの読み込みが遅くて2秒くらいかかってる
  • Google Analytics使ってる

まず始めに影響の大きかった2つについて検討した。

  • 明らかにjqueryの読み込みが遅くて2秒くらいかかってる
  • zeptoに置き換える
  • あとでminifyするつもりだったのでCDNではなくローカルにとってくる
  • Google Analytics使ってる
  • 表示には関係ないので除去

これらで2秒くらい改善した。

次に非同期でコンテンツを取得しているところの通信が気になったので調査した。 「注目のコンテンツ」という箇所が実際には広告で別のバックエンドから取得しているようだった。 ここでスタッフにソーシャルハッげふん、げふん、要件を定義してもらい静的コンテンツにしてしまっていいという答えをえた。 要件定義.png この改善で60msくらい減った。この変更はあとからQ&Aにのったけど見てなかった人とはここで差がでたと思う。

ここまでやるとおかしな接続はなくなってCSSファイルのサイズが気になってきた。 以前Qiitaでそんなこと書いてるようなことを覚えてたのでググった。

結果としてダメcommonだということが判明したので、それ中心にCSS全体として50%くらい?不要な記述があったので削った。そしたら必要なものもあったらしくレイアウト崩れてしまったのでインスペクタで確認しつつ部分的に戻した。

猫の日 #とは

/* 猫の日対応@2/22が終わったら消す */

CSSの中身はさわり始めると地獄になりそうだったので、見た目崩れていないことの確認以上は深入りをしなかった。

1日目午後にやったこと

表示に必要のないJSを削除。 minify系のウェブサービスを使ってCSSとJSを縮小。 CSS Spriteを検討したが、詳しくなかったので今回はやめた。 サーバのnginxがそんなに性能よくなかったぽいのでTCPソケットを減らすために画像をdataスキームに埋めこむ。

たんぽぽわーくで日が暮れる。

15時くらいに中間計測があり、その時点での評価結果が出された。 今回は連番にIDが振られており、そのIDがそのまま評価用のURLにも使われていたので、かつレギュレーションになかったので、上位のサイトを検証しにいった。 速いところはみんな似たようなことやってた。CSS Spriteやってる人もいて尊敬した。

最速のページ

<html>niconico(C++)</html>

1日目夜

作業やってもよいレギュレーションだったけど、疲れたので寝た。もう若くない。

2日目会場に着くまでにやったこと

いいかげんたんぽぽ疲れしたのでgruntを調べる。 grunt-contrib-uglifyとgrunt-contrib-cssminが使えそう。

2日目午前にやったこと

この日は競技時間が1時間半くらいしかないので大きな変更はあきらめて細かく修正することにした。 細かく成果物を生成するには手作業でminifyしてるとつらいのでgruntを導入した。 uglifyとcssminが他のminify系サービスより性能が良かったのが驚いた。

zepto外しのためにjQueryを想定しているコードの機能だけ抽出して代替コードを書きだす。が間に合わずに中止。 残り2分でhtml自体をminifyしてないことに気付く。ググったらgrunt-contrib-htmlminが。 とりあえず入れてREADME通りに設定して動かす。何か成功したっぽい。時間ないから 確認せずそのままアップロード

そして結果発表を待つ。

結果発表

最速になりました。そして戀塚さんの目にとまったらしく審査員特別賞もいただくことになりました。

何が決め手だったか

計測結果からの推測になってしまうのですが、LTE回線だったこと、計測は10回読んだ平均を使ったことから、 アセットをページに全て展開するのではなく、ある程度の粒度の少数のファイルに分けることでの並列の効率化が効果があったと思われる。あと AppCache これは計測方法が詳細不明だったので有効かどうかは不明だったけど、うまく刺さったようで爆速になった。たぶんこれが随分大きな要因。ただ個々のサイズが大きいとレンダリングが終わるまでに時間がかかるのは明白なので、極力サイズを減らす努力は無駄じゃなかったと信じたい。

おわりに

そもそもチューニング厨は参加自粛するべきイベントだったのではないかと思い始めましたが、司会進行の方が私のいま住んでる地方ラジオに枠をもってるとか何かよくわからないつながりがあったり、表彰式に偶然ymotongpooがいたりで終始中々面白かったので良しとします。 再度になりますが、参加された方々、運営されたスタッフの方々、ほんとうにありがとうございました。 :)

デブサミDay0メモ

センサー系のカンファレンスで参考になった内容をメモ

  • 目的が分かりやすい。コンセプトが一つしかない。
  • うまくいかなくてもそんなに気にならないようなインターフェースにする。 センサーの精度はまだそんなに高くないので誤認識しやすい。それでもユーザを不快にさせないような仕組みを考える。

Image.jpgImage2.jpg

テストのためのIO抽象

先日のGoken vol.14でJxckさんから良いことを聞いたのでメモに残す。

定義

何はともかく定義を。

type rwcMock struct {
    bytes.Buffer
    Closed bool
}

func (m *rwcMock) Close() error {
    m.Closed = true
    return nil
}

Goは、ある構造体の埋め込むことでその構造体のように振る舞え、そのオブジェクトに対してメソッドが定義されていたらインターフェースを満たすという機能がある。 bytes.Bufferの定義は、

```go:buffer.go type Buffer struct { // ... }

func (b *Buffer) Read(p []byte) (n int, err error) { // ... }

func (b *Buffer) Write(p []byte) (n int, err error) { // ... }

となり、これはio.ReadWriterインターフェースを満たす。

```go:io.go
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type ReadWriter interface {
    Reader
    Writer
}

そしてrwcMockはio.ReadWriteCloserインターフェースを満たす。

```go:io.go type Closer interface { Close() error }

type ReadWriteCloser interface { Reader Writer Closer }

## いかに使えるのか

ここでnet.Connとos.Fileの定義の抜粋を記す。

```go:net.go
type Conn interface {
    Read(b []byte) (n int, err error)
    Write(b []byte) (n int, err error)
    Close() error
    // ...
}

```go:os.go type File struct { // ... }

func (f *File) Read(b []byte) (n int, err error) { // ... }

func (f *File) Write(p []byte) (n int, err error) { // ... }

func (f *File) Close() error { // ... } ```

一目見て分かるように、これらのオブジェクトはio.ReadWriteCloserインターフェースを満たす。

つまり入出力でこれらのオブジェクトを使う箇所で型をio.ReadWriteCloserにしておけば、テストダブルとしてrwcMockを使えることを意味する。

Pythonにおけるfileオブジェクトの代わりにStringIOオブジェクトを渡して、内容を検査するのと同様なことがGoでもできる。

補足

POSIXではもっとプリミティブなファイルデスクリプタ、型でいうとuintptrまで抽象化することが可能なのだが、現状のGoはソケットのファイルデスクリプタを公開しておらず、内部的にはnetFDとして定義しているのだが、そとからはos.Fileでしか操作することが出来ない。

補足2

ここまで書いてから気付いた。net.Connインターフェースには定義されていないが、TCP/IPやUnixドメインソケットのConnオブジェクトにFile()メソッドが定義されていて、os.Fileオブジェクトが返るようだ。 つまり、ソケットでできることはファイルオブジェクトででもできる。 どちらにせよrwcMockのテストにおける有用性は変わらない。