2013年12月31日火曜日

2013年を雑に振り返り

今年もあと1時間弱で終わりそうってことで振り返りをしてみる。もう1月1日まで時間がないのですごく雑になっちゃったw

仕事

  • ORMapper作った
  • サービスの新規立ち上げ3本をお手伝い
  • Chef覚えた
  • Fabric覚えた
  • MySQL 5.6実戦投入した
  • Jenkinsが嫌いになった

プライベート

まとめ

今年一番の思い出はISUCONの予選に惨敗したことだった。自分のショボさを思い知らされた&界隈で凄腕とされるエンジニアの人たちは本当にすごいんだなぁということをすごく痛感したイベントだった。もっと貪欲になってスキルを磨かないとなと思ったのと、とにかくレベルの高い人たちと一緒に仕事をしたいと前にも増して思うようになった。あと、仕事では相変わらずやっていることが1.5年前と変わらなくなってきたので、今年の年末年始はUnityで糞ゲーでも作ろうかと思っている。しかしUnity覚えることが多くて大変&糞ゲーを作るにも才能が必要なのだと感じているところ。

プライベートでは猫(ししまる)を飼い始めたのが一番大きかった。猫なのにやたら人なつっこくて(家に帰ってくると玄関までダッシュしてくる)、本当に毎日癒やされている。奥さんともいっつもししまるの話ばっかしている。

年越し蕎麦を狙うししまる

そして来年は家族構成がインクリメントされるので、家でも仕事ももっと濃い時間が過ごせるように頑張っていこうと思う。来年も皆さまよろしくお願いします。

2013年12月30日月曜日

ncコマンドでmemcachedにコマンドを送りつける

開発用のサーバでmemcachedのキャッシュを全消しするために flush_all をよく使うんだけど、telnetで対話的にコマンド送り込むのだるいのでそういう場合はnc(netcat)を使えばいいよー、という話。

下記はlocalhostの11211でLISTENしてるmemcachedにflush_allを送りつける例。

$ echo flush_al | nc localhost 11211

2013年12月28日土曜日

IntelliJ IDEAを使いやすくするための設定とか

3ヶ月前ぐらいからPython、RubyやJavaScriptなどのスクリプト言語でコードを書く時はIntelliJ IDEA(有償版)を使うようになった。以前はEmacsユーザだった。乗り換えた理由としては

  • IntelliJを試しに使ってみたらけっこう使い勝手が良かった
    • 例えばPythonだと、SDKの設定さえすればimportしているモジュールのメソッドに簡単にジャンプできたり、変数や関数などのシンボルも可能な限り補完してくれる
  • Emacsの設定をするのが辛くなった(プログラマとして恥ずべきことであるのは知っている)
  • IntelliJが様々な言語に対応しているため、これ一つあれば大丈夫感が強い

などだろうか。有償版はパーソナルライセンスで2万円ぐらいだけど、そのぐらい払う価値はあるかなぁと今のところ感じている。ただ、そんなIntelliJさんもやっぱり使いづらいところはあるので、個人的に必ず設定している項目を書いてみる。なお環境はMacで、IntelliJのバージョンは13。

概念とか

Eclipseユーザの人はEclipseユーザの為のIntelliJ IDEA QA を読むといいと思う。Eclipseとの違いが書かれている。ちなみに自分はJavaを書く時はいまだにEclipse使ってるw 長年蓄積された手癖というものがどうにも捨てられない。

プラグインのインストール

IntelliJでPythonやRubyを書くにはプラグインをインストールする必要がある。PreferencesのPluginsからポチポチ選択する。自分が入れているのは下記。

  • Python
  • Ruby
  • NodeJS
  • Scala
  • ReStructuredText

IDEAが使うJVMを変更する

IntelliJはJVM上で動く。そのJVMを変えたい場合は

/Applications/IntelliJ\ IDEA\ 13.app/Contents/Info.plist を下記のように修正

<key>JVMVersion</key>
<string>1.6*</string>
       ↓
<key>JVMVersion</key>
<string>1.7*</string>

IntelliJ IDEAのヒープサイズ

Version 12以降は /Applications/IntelliJ IDEA XX.app/bin/idea.vmoptions を ~/Library/Preferences/IntelliJIdeaXX/ にコピーして編集する。自分は下記のようにしてる。

-Xms768m
-Xmx768m
-Xmn384m
-XX:MaxPermSize=384m
-XX:ReservedCodeCacheSize=96m
-XX:+UseCodeCacheFlushing
-XX:+UseCompressedOops

設定のimport/export

Preferences -> File -> import settings / export settings

でできる。SDKの設定はexport/importしない方が無難かもしれない。

エディタのタブの設定

Preferences -> Editor -> Editor Tabs

以下の2つの設定をデフォルトから変えている。

  • Show directory in editor tabs for non-unique filenames: ファイル名が同じものを開いている場合ディレクトリ名を表示
  • Mark modified tabs with asterisk: 編集されたファイルのタブにはアスタリスクをつける

エディタ上でコピペした時に自動でフォーマットしない

コピペする時に勝手にフォーマットしてくれて元のテキストの体裁を維持してくれない場合があるので、自分はCmd + V でペーストした場合の挙動を変えている。

Preferences -> Keymap -> Paste Simple にCmd + V を割り当て

英語のスペルチェックをオフ

造語などにいちいち波線がついてうざいのでオフにしてる。

Preferences -> Inspections -> Spellingのチェックを外す

クォートやカッコを自動挿入しない

自分はこういうのオフにする派。

Preferences -> Editor -> SmarkKeys -> Insert pair bracket

エディタで表示しているファイルとプロジェクトのツリーの選択ファイルを同期する

Eclipseではデフォルトで有効になっている機能。ファイルが多いプロジェクトだとこの機能ないとつらい。

  • プロジェクトを開いた状態で、projectの設定(歯車みたいなやつ)をクリック
  • Auto Scroll from Sourceにチェックをつける

2013年12月14日土曜日

環境をリセットする

最近日々思っていることを文章にしてみる。特に深い意味はないし結論もない。

何年も同じ会社や部署にいると、自分の立ち位置・イメージみたいなものが凝り固まってくる。「この人はすごいデキる人だ」「この人と一緒に仕事をすればいいものが作れる」とか、もしくはその逆。こうなってくると自分は定期的に「ああ、リセットしてゼロからやり直したい」と思ってしまう。いわゆるダーマの神殿行く的な?おそらく頻繁に転職する人だったり部署異動する人はこういうリセット志向が強い人だと思う。

例えば転職して新しい会社でまわりは誰も知らない人だと、早く一人前に仕事できるようになってまわりからの期待に応えたいと思うし、そうやって信頼を勝ち取って行くのは自分にとってもすごく嬉しい。何より転職前に比べてモチベーションは圧倒的に高い。

なので、頻繁に転職するいわゆるジョブホッパーな人は、ネガティブに見れば「どこの組織でもうまくやれてない」可能性もあるんだけど、上のようなリセット力の高い人もけっこういるんじゃないかなぁと思うし、そういう人はいろんな環境・仕事をやってて経験豊富で優秀だったりする。でも世間ではあまりこういう考え方が浸透していない気がしていて残念。

2013年12月7日土曜日

MacでターミナルからSublimeTextでファイルを開く

こんな感じでPATHが通っているところにsublコマンドのシンボリックリンクをはってやる。

$ ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl /usr/local/bin/subl

で、あとはsublコマンドでファイルなりディレクトリを開けばOK。

2013年10月20日日曜日

標準出力・標準エラー出力をキャプチャするPythonのライブラリを作った

https://pypi.python.org/pypi/iocapture

PerlでいうCapture::Tiny みたいなやつのPython版が欲しかったので作ってみた。Python3にも対応させた(つもり)。

ここ3ヶ月で取り組んだ技術とか

去年から新規のソーシャルゲームの立ち上げのヘルプをしていて、つい最近も1つリリースした。リリースも何とか無事に終わりデスマも落ちついたので、ここ3ヶ月ぐらい主に仕事で使ってきた技術をここらでまとめておこうと思う。

Java

うちの会社はサーバサイドの言語はJavaかNode.js(JavaScript)が多い。自分がたずさわっているプロジェクトはJava。正直Javaなんて面倒なんでやめたいんだけど、これ使えばけっこう開発が楽になる、っていう技術が2つ。

JRebel

いわゆるホットリローディングを実現してくれるソフトウェア。IDEに組み込んで使う。該当クラスのソースを編集すると自動的にクラスを再ロードしてくれる。有償製品だけどJRebel Socialなんていう謎なライセンスで無料で使うことができる。

Lombok

会社のブログ に概要を書いたので見てくらはい。

NewRelic

パフォーマンス解析ツール。負荷テストをしながらNewRelicを使ってどこがボトルネックかを調査した。任意のURL(に対する処理)を一定時間プロファイリングするX-Rayっていう機能が便利だった。ただNewRelicの全機能の10%も使ってないと思われる。

Vagrant

うちの会社はChefでサーバ構築するようになってきていて、自分もやっと真面目にChefに取り組んでみた。VagrantはChefのレシピをテストするのに使っていた。

$ vagrant up
$ vagrant provision

で cookbooks がゲストOSに転送されてchef-soloが実行される。すごいシームレスに統合されていてすごいなぁと思う。ドキュメントもしっかりしていて特に躓くこともなかった。

Fabric

Python版のCapistranoみたいなやつ。最初はShellScriptでディプロイスクリプトを書いていたんだけど、複雑な処理をやらせるにはちょっと役不足だったので、代わりにこれを使った。@parallel っていうデコレータつけるだけでタスクが並列で実行されるのがよい。

Grunt

最近流行っているnode.js製のJavaScript関連のタスクランナー。JavaScriptのminifyとかconcatするのに使った。

ChatWork

Skypeの代わりにこれを使っていた。ただ正直Skypeの方が好きだ。HipChatはいつか試したい。

IntelliJ IDEA

JavaのコードはEclipseで書いてたんだけど、PythonやRubyのコードはIntelliJで書いてる。ちょっと設定するだけで補完が利くようになるのがいい。

2013年10月7日月曜日

#isucon の予選に出場して惨敗してきた( ー`дー´)キリッ

@la_luna_azul さんと@oranie さんとでISUCON1日目に参戦してきた。結果から言うとトップと約8倍差がついて惨敗10位ぐらいには入れるかなーと思ったけど考えが甘かったし、準備も実力も足りなかった。

準備

  • bitbucketにプライベートリポジトリ作って、そこのWikiに事前にやったほうがいいことなどをまとめたりした。
  • 必要そうなRPMを事前に作ってもらった

やったこと

  • 言語はPythonを選択
    • Python 3.3.2が使われていたのが予想外だった
  • ソースはすべてbitbucketのプライベートリポジトリに突っ込み、簡単にディプロイするようにした
  • 最初の方はset global general_log =ONにしたり、mysqldumpslowやapachetopで傾向を把握
  • memcachedが11212で立ち上がっていたので、アプリからmemcachedへの向き先のポートを変えた
  • my.cnfのチューニング
    • クエリキャッシュ多め
    • あとは一般的なチューニング
  • SELECT username FROM users WHERE id = ? みたいなクエリが多かったのと、userのレコード数が400だったので、usernameをアプリ起動時に全件取得してmemcachedに全て突っ込むようにした
    • Flaskには @before_first_request なんていう便利なデコレータがあることをこの時初めて知る
  • memosのuser, created_atにインデックスが貼ってなかったのではった
    • 複合インデックスより個別にインデックスを貼ったほうがなぜか速かった
    • ただしbenchコマンドを実行するとテーブルが初期化されることに14時ぐらいまで気付かなかったorz
  • 静的ファイルをApacheで返すようにした
    • 最後にはnginxに変更。ただしスコア的には変わらず
  • SELECT count(id) AS c FROM memos WHERE is_private=0 みたいなカウントをmemcachedに突っ込んだ
  • 自家製のスクリプトを使って下記のようにどのURLが全体として遅いのかを把握
  • MarkdownをHTMLに変換する処理がbin/markdownコマンドをサブプロセス起動で行っていたので、これをPythonのMarkdownモジュールを使って変換するようにした。結局、これが一番スコアに効いた
  • SELECT COUNT(*) しているところを SELECT COUNT(id)に変えた
  • SELECT * FROM users WHERE id=? をキャッシュするようにした
  • NewRelicのインストールを試みるもうまくいかず頓挫
  • SELECT * FROM memos WHERE is_private=0 ORDER BY created_at DESC, id DESC LIMIT 100 みたいなクエリがあったので、created_atとidをASCでソートできるように逆順カラムを作った。ただしこれは最後のほうにbenchmarkコマンドでFAILしたので諦めた
  • geventをインストールしようとするも頓挫
  • gunicornのworker数の調整

反省点

  • 事前の打ち合わせで @la_luna_azul = フロント回り、@oranie = データベース回り、@oinume = アプリ回りと役割を分担してしまっていたため、「その時の最大のボトルネック」を直すことより各々で担当領域のことをやってしまっていた。ボトルネックを全員で全力で解決するアプローチのほうがこういうケースだと良かったのでは?と反省会で話していた。
  • EC2のインスタンスを3人分作ってやっていたので、おのおのが行ったサーバの設定変更などを反映させるのに無駄に時間がかかってしまった。本番環境とテスト環境、の2つぐらいで良かったのでは?と思う。
  • 「このURLが遅いしアクセス数も多い」みたいなことまでしか把握せずに、アプリケーションのどこがボトルネックかを正確に追ってなかったので、効果が高いチューニングをあまり行えなかったような気がする
  • Markdownのサブプロセス問題に気付いたのが14:00ぐらいだった。最初からソースを全部読んでいればもっと早くここは直せたように思う。
  • NewRelicインストールできなかった

感想

  • 自分の力のなさがわかっただけでも参加した甲斐があった
  • コードの修正は意外と早くできたので、もっと怪しい箇所のあたりをつけるのを的確にできるようになりたい(ので修行します)
  • 正攻法では突き抜けたスコアは出ないだろうなぁと思ったけど意外とそうでもなさそうだった(1, 2位の人たち以外)
  • あの問題やベンチマークツールを作るの大変だっただろうなぁ。運営の皆さまお疲れさまでした!

2013年9月20日金曜日

PyCon APAC 2013 2日目に行ってきた(2) #pyconapac

ちょっと間が空いてしまったけど、PyCon APACの2日目の後半。Pythonでハードウェアを操る話、ちょうどRasberryPiを買ったので耳寄り情報が多かった。とりあえずpyserialは入れとけと。

あとDjangoのデバッグの話は、django-debug-toolbarなど興味深かった。これって他のフレームワークにも移植されてて、Flask版やBottle版もあるみたい。そういえばBottleはwerkzeugで動かすこともできたような。

PythonでハードウェアをWebAPIにした話

  • 北神雄太さん @nonNoise
  • 所属:ArtifactNoise
  • 職業:発明家
  • 主な開発:Elpis Framework
  • スライド
気になってる話題
  • Tessel
    • JavaScript, Nodeが動くらしい
  • Arduino YUN (アードゥイーノ ヤン)
    • Linuxが乗ってる
  • GALAXY Gear
  • Nymi
ハードウェア界隈の話
  • Arduinoの進化
  • RaspberryPiなどのカード型PCの登場
  • RaspberryPiのPiはPythonのパイらしい
  • PyGameが標準で入っている!
  • Linuxなら標準で入っているので、カード型PCでPythonを動かし、特殊なハードウェアをコントロールする新しいムーブメント
Pythonでハードウェアを扱う方法
  • Pyserialを使う。簡単
  • USBが刺さった時にどっちのポートが刺さったかわからない
  • USB Serial変換チップ
    • USBがttyとして認識される!
    • USBのドライバを書かなくてすむ
  • マザーボードのIOを直接操作できる
ハードウェアとのやりとり
  • 基本的にはコマンド方式がほとんど
    • 1(前へ進む), 2(後ろへ進む)
ハードウェアをWebAPIにする

(メモあんまり残ってない)

ser.getline()

Django最速デバッグ指南

django-pdb
  • -pm
    • Exception出たらデバッガが起動する
django-devserver
  • SQLのクエリのログ
  • リクエストの情報
  • プロファイリング情報

などをコンソールに出力。

django-debugtoolbarはテンプレートを使っていないと表示されない。APIだとデバッグ情報は見れない。あとJSが走るのでJSゴリゴリ書いているとエラーになる可能性がある。

runserverwerkzeug
  • Flaskの人が作っているWSGI実装
  • ブラウザ上でインタラクティブなデバッガーが使える
logging
  1. logger.error(Invalid code: %s%azunyan)
  2. logger.error(Invalid code: %s,miotan)

2.が正しい。理由は2.で書いておくとログ集約ができるから。

重要な点

  • 正しく使う
  • ログレベルの認識を一致させる
  • ログの頻度の統一

debug,info,warning(warn),error,critical(crit)

  • debug
    • 開発時のみ出力
  • info
    • ファイル出力
  • warning
    • 機能は動作してるけど何か間違っている
    • 処理は継続できるけど何かがおかしい
    • バリデーションエラーぐらいの認識
  • error
    • 500エラー
    • バッチが落ちるレベル
  • critical
    • 使わない
その他開発・運用で使っているツール
  • PyCharm: Python向けIDE(IntelliJ)
  • Sentry: ログ収集プラットフォーム
    • ログを集約してメールで通知とか
まとめ
  • デバッグには何が起こっているのかを理解するのが大事
  • ツールを正しく使えばデバッグ時の負荷を減らせる

2013年9月17日火曜日

PyCon APAC 2013 2日目に行ってきた(1) #pyconapac

今日も基調講演は聞けなかったんだけど、その日のうちにYouTubeにアップされていたので早速見てみたら、リアルタイムで見れなかったのがすごい悔やまれる内容だった。Pythonが遅いとか、信頼できるシステムを作りにくいとか言われるけど、本当この人の言っている通りだなぁと思った。自分は普段Java書いてて、Javaはたしかにスレッドがあるから速いしスケーラブルだけど、その速さ・スケーラブルさを必要とするシーンって一体どのぐらいあるんだろう?っていうのはいつも思っていて。よく「TwitterがRailsやめてJVMに移行したからこれからはJVMの時代だぜヒャッハー」みたいなことをいう人がいるけど、「TwitterレベルのトラフィックだからJVMが必要」なんであって大抵のケースにはJVMは必要ないんだよねー。だってDropboxですらPythonなんだもの。

あと、清水川さんの2.5から3.3まで対応させる話、ちょうどtomahawk をPython3対応しないとなぁと思っていたので渡りに舟だった。sixっていうモジュールは名前は知っていたんだけどあそこまで便利に使えるヤツだとは知らなかったので、その話が聞けただけでも今日は来た甲斐があった。

Keynote: One Million Lines of Python

  • Rian Hunterさん
  • Dropboxの3人めの社員
  • 最初の仕事はLinux版のデスクトップクライアントを作ることだった
  • 動画
  • C, Python, Haskell を書く
  • Python makes me feel good
動的型付け言語ではRobustなシステムは作れない?
  • You can build a reliable foundation with Python
  • We did (かっこいい!)
「Pythonが遅い」問題
  • あなたのコードのボトルネックはCPUバウンドな処理なのか?
    • たいてい違う
  • CPUバウンドじゃないなら、Pythonが遅くてもそれは関係ない
  • 本当にCPUバウンドなら、その部分だけCで書けばいい
GIL
  • multithreading以外にもmultiprocessingがある
Dynamically typed じゃなくて Duck typing
  • これ に感銘を受けた(The Zen of Duck Typing)

Python2.5から3.3で動作するツールの作り方

  • @shimizukawa さん
  • ビープラウド所属
  • スライド
  • 題材は sphinx-intl
sphinx-intl

国際化機能をサポートするツール

  • potから言語別poの生成、更新、ビルド
  • モチベーション
    • sphinxの対応バージョンが2.5-3.3
  • 本体500行ぐらい
2.5から3.3の違い
  • ライブラリの違い
  • ビルトイン関数の違い
  • 文法の違い
ライブラリの違い
  • optparse(まだある)
    • argparse(2.7以降、3.2以降)
  • OrderedDict(2.7から)
optparseとargparse
  • optparseよりargparseの方が使いやすい
  • 2.7, 3.2以降で標準ライブラリになった
    • pip install argparse でインストールできる
  • sphinx-intl ではoptparseをまだ使っている
    • なるべく標準ライブラリで動かしたいので
OrderedDict
  • Dicionaryだけど順番を保持してくれる便利なアレ
unicode, str, bytes
  • Python2のstr()はPython3のbytes()
  • 2のunicode()は3のstr()
funccodeと code _

関数オブジェクトの属性を取る
関数の引数の数や変数名とかいろいろ取れる

argcount = spam.func_code.co_argument
spam.func_code.co_varnames[:argcount]

argcount = spam.__code__.co_argument
spam.__code__.co_varnames[:argcount]
callable
  • 3.0,3.1で組み込み関数から消えたが3.2で復活した
  • そのオブジェクトが関数として呼び出し可能かどうか判定する
  • なんで削除されたのだろう?
try:
   callable = callable
except NameError:
   def callable(obj):
      __mro__みて__call__があるか調べる
execfile消滅
  • evalみたいなもん?
  • open(), read(), compile(), exec() をやれば同じことができる
  • execもPy3で文から式に変わった
with
  • 2.5から fromfuture import with_statement
  • 2.6以上はimportしなくても使える
print文とprint関数

Py2はprintは文

# Py2
> print 'spam', 'egg', 'ham'
spam egg ham

> print('spam', 'egg', 'ham')
('spam', 'egg', 'ham')

# Py3
> print('spam', 'egg', 'ham')
spam egg ham
print >>sys.stderr, ,
...
print 'done'

print('image', filename, 'loading...', end=' ', file=sys.stderr)
data = load_image(filename)
print('done.')
  • fromfuture import print_function
    • python2.5では使えない
    • じゃあprint関数を自分で実装するか!
じゃあどうやって2でも3でも動かすか
  • 2to3を使う
  • 両対応コードを書く
  • sixを使う
    • 2 x 3だからsixっていう名前らしい
2to3
  • Py3には2to3が用意されている
  • Py2をPy3に変換するプログラム
  • setuptoolsはsetup(2to3=True)って書いておくとインストール時に変換できる
Pros
  • 既存の資産を簡単に活かせる
Cons
  • 2to3は遅い
  • テスト実行のために毎回2to3を動かす必要がある
  • Py3でのみエラーがある場合、変換後のコードで問題があると面倒
両対応コード
  • 2to3がいらない
  • デバッグしやすい(重要)
  • Py2.6以降ならだいたいPy3互換の書き方ができる
  • Py2.4対応は可能だが絶望的
  • Py2.5を投げ捨てたくなる
  • 差異の吸収を自前で実装するのはつらい
    • print関数とかね
sphinx-intlはどうしたか
  • 諦めてsixを使った
six
  • 1.4.1 release (2013/9/2)
  • 2.4から3.3まで対応
  • 移動や名前変更は内部でバージョン判定して呼び直している(movesパッケージ)
  • execfileだけは自前で実装する必要がある
sphinx-intlで避けられなかった2to3
  • sphinxのconf.pyはユーザが書くものなので、2か3で書いてあるかわからない
  • execfileで読み込んでエラーが出たら2to3で変換する、という方法で対応した
パッケージングにおける課題
  • distlib登場。3.4で同梱予定
  • wheel登場。eggの代わりのパッケージのバイナリフォーマット
  • distribute廃止。setuptoolsに統合された。setuptoolsがPy3対応
Py2,3で動作するsetup.pyを作る
  • Py2,3で動作するようにしておく
  • 2to3もsetup.pyに対しては動かせない
  • 特定バージョンの場合に依存パッケージがある場合は自前で定義する
requires = [ 'six', 'polib', 'sphinx' ]
if sys.version_info < (2, 7):
   requires.append('ordereddict')

transifexってなんだろ?

  • 対応しているバージョンはsetup.pyのclassifiersにかこう!
    • Python3をclassifi入れるとpypiのロゴに3がつく!!
まとめ
  • Python2.5はそろそろ消滅するべき!
    • 会場内には一人しかいなかった
    • AppEngineはちょっと前まで2.5しかサポートしてなかった
    • CentOS5は2.4, CentOS6は2.6
  • 2to3は大変
  • sixは便利
質問
  • いろんなバージョンでテストするにはどうすれば?
    • テストはtox使うといろんなバージョンでテストできるので便利

Pythonサポーターズ

技術評論社

売り上げランキング: 57,978

2013年9月16日月曜日

PyCon APAC 2013 1日目に行ってきた(3) #pyconapac

というわけで1日目の最後のエントリー。1日目は濃い目のトークが多かったせいか終わった後の疲労感がハンパなかったっす。

実践C拡張モジュール開発

C拡張モジュールを書く意義について
  • Pythonでないといけないのか?
    • Java, Go, Lispなど
    • Rustはやめておけ
  • Cのライブラリを呼ぶだけならctypesでおk
  • 今ならばPyPyも検討
  • 必要な箇所だけCで書く高速化
  • パフォーマンス
    • Cコンパイラによる最適化の恩恵
なぜCythonではダメなのか?
  • 学習コスト
  • 構文などCython自身の知識が必要
  • C/APIの知識も必要
  • Cデバッガで追うことになった場合の対応が難しい
開発環境の準備
  • C/API ドキュメント
  • コンパイラ
  • 開発用Python(debugビルド)
    • ビルドに必要なライブラリ
    • virtualenv, py.test or nose
  • デバッガ(gdb)
  • Valgrind
./configure --prefix=~/opt/py33 --with-pydebug --with-valgrind
make
make install
DebugモードのPythonについて
  • メモリプールの無効化
    • 無効にしないとリーク検出が難しい
  • 生存Object数の表示
  • closeされていないFDなど各種warning表示
  • Valgrind
その他準備
  • エディタ
  • coredumpを吐くようにしておく
$ ulimit -c unlimited

setuptools, distribute

$ python setup.py develop

開発ディレクトリがライブラリのパスに入る

実際の開発

C, Pythonで別々にしておく

  • src
    • Cソース・ヘッダー
  • jega - pythonパッケージ

ディレクトリはC/Pythonで分けた方が無難

setup.pyの役割
  • distutilsを使ってモジュールをビルドするためのもの。Makefileはいらない
  • 環境の判別
  • コンパイルするソース指定
  • コンパイルオプションの設定
    • ライブラリのヘッダー、リンク
  • configure なども実行できる
  • C拡張以外のPythonパッケージのインストール
まずutil関数を書いておく
  • OS,Pythonのバージョンアップチェック
  • Cファイルの一覧作成
  • デバッグモードなどマクロの切り替え
  • 他のライブラリのヘッダーファイルの検索
Python C/API
  • 略語が少ないため、コードが読みやすい
  • ユーティリティ関数も準備されている
  • 2.x, 3.xでもほぼ変わらない(安定)
  • ドキュメントもしっかりしている
コードの記述

ソースファイル
* 1機能毎にわける
* シンプルなファイル名
* ヘッダーとソースは用意する

  • 構造体
    • PyObjectの場合は大文字から始める
    • それ以外は_tで終わる
  • 接頭語
    • モジュール:ExampleMod_xxxx
    • クラス名_メソッド名
static PyMethodDef LoopObject_methods[] = {
   { "switch", ... }
}

Cであるので必ず返り値を返し、エラーであるかをチェックする

  • 例外が発生している場合には必ずNULLを返す
  • Noneを帰す場合は、 Py_RETURN_NONE を返す
  • その他の場合:intでエラー時には負の数を返す

  • New reference

    • 参照が +1 されて返る
    • 通常のPythonコードもコレにあたる
  • Borrowed Reference

    • 参照カウントが上がらない
    • Tuple などがこれにあたる
参照カウントの規則
  • PyObject *型を返す関数
    • 必ず Py_INCREF をしてから返す
    • 呼び出し側で Py_DECREF するコードで統一
  • Borrowedは別関数として分ける
    • DECREF していいのかをわかりやすく
    • 内部で使いまわしたい
ThreadとGIL

Pythonから呼ばれる以上、スレッドセーフになっている場合がほとんど。N/W IOが走る場合は下記で囲んでおく

  • Py_BEGIN_ALLOW_THREADS
  • Py_END_ALLOW_THREADS
インスタンス継承
  • Cで作成したクラスをPython側で継承
その他
  • Cでも iter を使おう
    • PyObject_GetIter でiterを取得
    • PyIter_Nextで繰り返す
  • PySequence_Fast
    • 高速

DEBUGマクロを使おう

  • 関数の最初、最後にかならずログを表示
  • オブジェクトの生成・削除のログは必ず取る

マクロによる分岐

PyBytesString使う

質疑応答
  • まずはPythonで書いてみて、本当に遅いか判断する
  • Pythonで書くのが大変だと、Cだとさらに大変になる

2013年9月15日日曜日

PyCon APAC 2013 1日目に行ってきた(2) #pyconapac

昨日のPyCon APAC 2013 1日目に行ってきた(1) #pyconapac に行ってきた、の続き。

Interrupt-Driven programming

スライドはまだ上がっていないっぽいんだけど、だいたいこれ と同じだと思われる。SIGALRMによるタイムアウトのハンドリングはPythonだけではなく一般的なUnixであればどの言語でも使えるのでよい手法だなーと思った。それを使いやすくしたのがinterruptingcow でこれは便利そうだと思った。全体的には英語+喋るスピードが速くてほとんど聞き取れなかったけど、スライドの内容はだいたい理解できたと思う。

はじめに
  • bitbucketはDjango
  • githubbitbucketのAPIのレスポンス時間が比較された
    • bitbucketが遅いという内容
  • レスポンスタイムでaverageは見るな
  • slow requests have a big impact
    • ユーザをいらつかせる
    • APIクライアントを壊す(timeout)
    • Rants on Twitter
    • foncus on the remining 2% instead.
logging timeouts

タイムアウトをログに記録する。

コードのイメージ

def handler(*args):
    raise Excepiton("Request timed out")

signal.signal(signal.SIGALRM, handler)

signal.setitimer(signal.ITIMER_REAL, 28)
try:
    アプリケーションの処理
finally:
    signal.setitimer(signal.ITIMER_REAL, 0)

→Tracebackが得られる!あとは遅いところをひたすら治す

  • legacy/bad code often resists refactoring
  • Unpredictable input
interruptingcow

https://pypi.python.org/pypi/interruptingcow

さっきのSIGALRMのあれをモジュールにして使いやすくしたもの。

from interruptingcow import timeout
with timeout(2, RuntimeError):
    なんか処理

みたいに書ける。

Scalable content linkification の例

def prelace(doc, pattern, tmpl):
    try:
        replace処理
    exception TimeoutExcepiton:
        pass
    return doc

with timeout(.1, TimeoutException):
     print replace(doc, re.compile, '<a href="">sss</a>')
django-timelimit

これもこの人が作っているモジュール。詳細は調べきれてない。

Unique Aspects
  • works with legacy code
  • Generic solution to different problems
  • Optimistic approach (EAFP vs LBYL)
まとめ
  • Page render times highly dependent on runtime factors
  • Page timeouts have a disproportinally large impact
  • Refactor, pre-compute, paginate, remove funcionality, etc
  • Time-box expensive code with cheap fallback
  • interruptingcow - time-box arbitrary Python code
  • django-timelimit - time-box Django template fragments
  • the average color of the universe isCosmic Latte

Fabric for fun and profit

Fabricはちょっと前にFabricの豆知識 で書いたようにちょっと触ってたのでわりと復習的な感じだった。

はじめに
  • We script everything
  • We ssh in and out servers all the time
  • FabricはPythonでsshでやっていたことを効率よくするためのツール
Fabricの簡単な説明
  • fabfile.py
  • @task
  • $ fab hello
Environment configuration
@task
def production();
    env.user = 'pdfs'
    env.hosts = [ 'example.com' ]

it is just python. we can mix python codes into system commands

Vagrant development
$ fab vargrant -- sudo service couchdb restart
Fabricの代替
  • Ansible - Chefのような構成管理ツール
  • Invoke - タスクを定義して実行

How the Mock library helps me developing client-side applications

MockというPython3.3から標準に含まれるようになったモックライブラリの説明と、外部のWebAPI呼び出しにおける使い方の説明。Mockって1回使ってみたんだけど個人的には微妙で(でもなんで微妙だったか思い出せない)、個人的にはpy.test のmonkeypatchより複雑なことをしたいときはFlexMock というものを使っている。3.3から標準添付されたので今後はやっぱりこっちを使ってみようかな。

  • @clsung さん from Taiwan
  • 仕事はフリーランス
はじめに
  • モックライブラリはmock以外にMox, Flexmockがある
  • mock はPython 3.3から標準ライブラリになった
Mockの特徴
  • Mock()
  • MagickMock()
  • @patch decorator
How mock helps me
  • Develop/test client-side applications
  • Server-side APIs (Google Drive v2)
  • Client-side request library (requests)
    • HTTP requests
    • HTTP

とかとか。

Mock open() - StringIO

with patch('__builtin__.open') as m:
    m.return_value = ...
patch.object(requests, 'requests', autospec=True).start()
patch('gdapi.utils.retry', lambda: x, y)
その他テストで使える有用なライブラリ
  • factory_boy
  • httpretty
  • testfixtures

2013年9月14日土曜日

PyCon APAC 2013 1日目に行ってきた(1) #pyconapac

にわかPython使いだけど、年に1回のお祭りなので行ってきた。今回のPyConはAPACというのがタイトルについているせいか、他の言語のカンファレンスより海外の人が多い気がした。Pythonは自分が知る限り日本ではあまり人気がないけど、海外ではけっこう使われているみたいなのでそういうのが反映された結果なのだろうか。とにかく、今日は全体的に濃い目の内容が多くてすごく参考になる話が多かった(でもその分脳力を使ったので終わったあとはぐったりしてた)。

仕事ではPythonを書くことはほぼなくて、プライベートでtomahawk のメンテをする時ぐらいしかPython書かないんだけど、個人的には一番好きな言語なので今回は参加してよかった。まだ終わってないけどすでに5000円分のもとは取れたように思う。

というわけで、自分が聞いたTalkのメモ。(長いので複数のエントリに分ける)

パッケージングの今と未来

aodagさん発表。スライド

Pythonでのパッケージ関連のツールの説明と使い方、およびその未来。あとsetup.pyの書き方をけっこう詳しく話していた。setup.pyは自分も他のライブラリのものをコピペしてるだけであまり深く知らなかったので今回勉強させてもらった。ので、いろいろ目から鱗の話が多かった。

最後に「RubyのBundlerみたく特定のディレクトリにライブラリをインストールするのは、Pythonだとvirtualenvとrequirements.txtを使うのでよい?」と質問させてもらったんだけど、このやり方でいいみたい。(というか今日の話聞く限りBundlerみたいなのはなさそうなので、これしかやりようないと思ったんだけど)

以下は手元に残っていたメモ。

  • pypaツール群
  • setuptoolsベースのパッケージング
pypa - Python Packaging Authority

pip, virtualenv, setuptools, pypi, distlib

$ pip install git+https://github.com/fabric/fabric@changeset 
setuptools/distribute
pkg_resources
  • メタデータを利用するためのライブラリ
  • パッケージに含まれるメディアデータの取得など
  • entry_point
setuptoolsとdistributeの関係
  • setuptoolsからforkしたのがdistribute
  • distributeがpy3対応などいろいろ
  • 2013 pycon US でマージ宣言し、pypaがメンテする
  • distributeコードベースでsetuptools-0.7
  • setuptools 1.1.5まで上がってる
  • distributeのことは忘れてあげてくださいww
setuptools
packages = find_packages()

packagesに自分でパッケージ羅列しなくても良い

entry_point

プラグインの仕組み

entry_point = {
   'console_scripts': [
       'hello=hello:greeting',
   ]
}

PasteDeploy, nose, cliff, setuptoolsのサブコマンドがこれを利用している。

egg
  • バイナリパッケージのこと
  • C拡張などのコンパイル済みライブラリなどを含める
  • ソースとメタデータをzipでアーカイブしたもの
  • pipでは扱えない
pypi (ぱいぴーあい)

CPANやrubygems.orgみたいなサイト

setup.py
  • install_requires
  • tests_require
  • test_suite
extra_require = {
    'testing': tests_require,
    'docs': docs_require,
    'dev': tests_require,+ docs_require,
}

今開発中のソースをパッケージとする方法。

$ pip install -e .

→これは python setup.py develop と何が違うんだろう?

python setup.py test egg_info check register sdist
pip install -e .[dev]

setup.cfg

[egg_info]
tag-build = dev

→パッケージに-devがつく

[upload_docs]
upload_dir = docs/build/html

とか。

エイリアス。

[aliases]
release = egg_info -Rdb
source = register sdist binary
binary = bdist_egg upload --show-response
$ python setup.py release source
パッケージングの未来
  • 関連PEPが出てきてる
  • wheel
  • distlib
  • Metadata 2.0
wheel
  • バイナリパッケージフォーマット
  • Metadata 2.0
  • bdist_wheel, egg2wheel, distlib.wheel などで作成
  • C拡張などを含まない場合はpy2,py3両方のユニバーサル構成も可能

Mavenでwarなプロジェクトからjarを作る

同僚にやってもらったことをブログに書く簡単なお仕事。

やりたいこと

warなプロジェクト(Webアプリケーション)を別のプロジェクトから使うため、WebアプリケーションなんだけどMavenでjarファイルを生成したい。

  • example-web
  • example-admin

のように2つのプロジェクトがあって、「example-webにあるクラスをexample-adminからも使いたい!」みたいな。

なお、使用するMavenは3.0.x以上を想定している。

pom.xml

pom.xml上では

<packaging>war</packaging>

のように通常のwarのプロジェクトとして定義するが、以下のmaven-jar-pluginをbuildpluginsに足すことで maven packageコマンドでwarファイルとともにjarファイルが生成されるようになる。

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <id>make-a-jar</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                        <configuration>
                            <excludes>
                                <exclude>**/*.xml</exclude>
                                <exclude>**/*.properties</exclude>
                                <exclude>**/SampleController*</exclude>
                            </excludes>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

↑のようにconfigurationでjarパッケージング時に除外するファイルや逆にインクルードするファイルを指定することができる。

やってみよう。

$ mvn package
...
$ ls -l target/war-jar-sample.*
-rw-r--r--  1 kazuhiro  staff     3535  9 14 03:06 target/war-jar-sample.jar
-rw-r--r--  1 kazuhiro  staff  3842928  9 14 03:06 target/war-jar-sample.war

ちゃんとjarファイルができている。

mvn installしたい

生成したjarファイルをローカルマシンのMavenリポジトリ(~/.m2/repository)に配置したい場合はmaven-install-pluginを追加する。

           <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <phase>install</phase>
                        <goals>
                            <goal>install-file</goal>
                        </goals>
                        <configuration>
                            <packaging>jar</packaging>
                            <artifactId>${project.artifactId}</artifactId>
                            <groupId>${project.groupId}</groupId>
                            <version>${project.version}</version>
                            <file>${project.build.directory}/${project.artifactId}.jar</file>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

やってみよう。

$ mvn install
...
$ ls -l ~/.m2/repository/net/lampetty/war-jar-sample/1.0.0-SNAPSHOT
total 7552
-rw-r--r--  1 kazuhiro  staff      234  9 14 03:09 _maven.repositories
-rw-r--r--  1 kazuhiro  staff      876  9 14 03:09 maven-metadata-local.xml
-rw-r--r--  1 kazuhiro  staff     3535  9 14 03:09 war-jar-sample-1.0.0-SNAPSHOT.jar
-rw-r--r--  1 kazuhiro  staff     7045  9 14 03:06 war-jar-sample-1.0.0-SNAPSHOT.pom
-rw-r--r--  1 kazuhiro  staff  3842926  9 14 03:09 war-jar-sample-1.0.0-SNAPSHOT.war```

ちゃんとjarファイルが ~/.m2/repository にできている。

mvn deployしたい

同様にリモートのMavenリポジトリにdeployしたい場合は以下のmaven-deploy-pluginプラグインを追加する。

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.7</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>deploy-file</goal>
                        </goals>
                        <configuration>
                            <packaging>jar</packaging>
                            <generatepom>true</generatepom>
                            <repositoryid>snapshots</repositoryid>
                            <url>${project.distributionManagement.snapshotRepository.url}</url>
                            <artifactId>${project.artifactId}</artifactId>
                            <groupId>${project.groupId}</groupId>
                            <version>${project.version}</version>
                            <file>${project.build.directory}/${project.artifactId}.jar</file>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

まとめ

最終的に出来上がったpom.xmlはhttps://github.com/oinume/war-jar-sample/ に上げてあるので、実際に試してみると良いでしょう。


Srirangan

アスキー・メディアワークス

売り上げランキング: 134,948

2013年9月9日月曜日

Fabricの豆知識

Python製のCapistrano的なツールであるFabric を少しだけ使ってみた。けっこう機能が多いので自分が使いそうなところをまとめておく。バージョンは1.7.0。

Fabricの基本的な機能

下記で任意のコマンドが実行可能
$ fab -H localhost -- uptime
またはfabfile.pyにタスクを書く
from fabric.api import run
def uptime():
    run('uptime')
$ fab -H host1,host2 uptime
$ fab --list

でfabfile.pyに定義されているタスク一覧を表示する。

ホストの定義はenv.hosts または env.roledefsで。
env.hosts = [ 'host1', 'host2' ]
# or
env.roledefs = { 'web': ['host1', 'host2'] }
並列実行
fab -P  -H host1,host2,host3 -- uptime
たくさんのホストにコマンドを実行する時にpasswordをきかれまくる場合

最初にパスワードを入力する

$ fab -I -H host1,host2,host3 -- uptime

引数にパスワードを渡しちゃう(セキュリティ的にオススメできない)

$ fab -p <password> -I -H host1,host2,host3 -- uptime
taskに引数を渡す
$ fab create_user:username=oinume
途中でエラーが発生しても処理を継続させる

-wで失敗しても処理を継続。デフォルトは失敗したらその時点でAbortする
fabfile.py の中で

with warn_only():
    pass

でも可

よくあるユースケース

リモートのサーバにコマンドを発行する
$ fab -H host1,host2,host3 -- mpstat -P ALL 1 1
サーバにファイルをアップロードする
from fabric.api import put

put('authorized_keys', '.ssh/authorized_keys')
rsyncでサーバにファイルをアップロードしたい
from fabric.contrib import project

project.rsync_project(local_dir='authorized_keys', remote_dir='.ssh/authorized_keys')

rsyncはローカルマシンから rsync コマンドを実行するだけのようだ。

rsyncでサーバからファイルをダウンロードする
  • rsync_project()の引数にupload=Falseを指定する
  • サーバが複数ある場合はダウンロード先の /tmp/my.cnf が上書きされちゃうので、ホスト名をサフィックスにつけている。env.host 現在実行しているホスト名が取れる。
from fabric.api import env
from fabric.contrib import project

project.rsync_project(remote_dir='/etc/my.cnf', local_dir='/tmp/my.cnf.' + env.host, upload=False)

Fabricのその他の豆知識

  • colorize-errors: エラーが発生したら赤字になる
  • hide=LEVELS: 出力する情報を制限できる。例えばhide=stdout,stderr,running と指定すると一切の情報が出なくなる
    • stdout: コマンド実行時の標準出力
    • stderr: コマンド実行時のエラー出力
    • running: 実行時の出力
  • -x HOSTS: 対象外にしたいホスト名を指定
  • -i PATH: SSHの秘密鍵を指定できる

Pythonサポーターズ

技術評論社

売り上げランキング: 12,569

2013年9月8日日曜日

某退職エントリーのコメントに対して思うこと

Web系エンジニア1年半ですが、このたびは転職する運びとなりまして、各位に連絡させていただきます - mizchi's blogのコメントで、
転職時に古巣の社名を出してdisるのは好きではない。あからさまなブラック企業なら悪くはないが、創業数年のベンチャーで給料が低いことに不満の言うのは何か違う気がする。
というコメントがあったんだけど、
エンジニア界隈的には僕と@udzuraがAimingの客寄せパンダならぬエンジニア寄せ的な位置にいたらしいので、僕自身の会社へのモチベーションが低い現状で人を誘うのも申し訳ないといった気持ちもありました。
ということが退職エントリーに書いてあるし mizchi さんはAimingに入ろうとしている若手に対して警鐘を鳴らしているのではないかなーと思った。単純に「古巣へのDISり」みたいに片付けるのはどうなんだろうって思った。このmizchiさんを一切知らないのでただの推測ですが。

2013年9月4日水曜日

Chromeで検索結果を英語または日本語だけにする

最近英語でググる事が多いので、基本的には検索結果は英語+日本語にしていて、どうしてもという時に日本語のみにしている。具体的にどうやって切り替えるかというと、Google検索時のURLのパラメータでlr というパラメータがあるので、これにlr=lang_en とすればよい。

英語の検索結果のみを表示
https://www.google.com/search?q=chrome&lr=lang_en
日本語の検索結果のみ
https://www.google.com/search?q=chrome&lr=lang_ja
英語と日本語両方の検索結果を表示
https://www.google.com/search?q=chrome&lr=lang_en%7Clang_ja

lrに複数の言語を指定する場合は%7C で区切れば良いみたい。あとは「英語だけで検索」とかを ge というキーワードで検索できるようにChromeの検索エンジンの管理で登録しておくと良さげ。

※ hl パラメータが検索結果の言語を切り替えるものだというブログ記事を多く見かけたけど、2013年9月時点では lr パラメータに変わっているっぽかった。

2013年8月26日月曜日

Bloggerを独自ドメインで運用する

ググって出てきた記事だとちょっと情報が古かったので。自分はドメインはvalue domainで取得しているので、value domainでの設定方法をば。

value domainのDNSの設定

まず、設定する独自ドメインが blogger.lampetty.net だとする。
  • value domainにログインする
  • メニューで「DNSレコード/URL転送の変更」をクリック
  • 対象のドメインを選択
  • 下記の2つのレコードを定義する(末尾の . のつけ忘れに注意!)
  • cname yoectwasv3gk gv-pqase73paobfnq.dv.googlehosted.com.
    cname blogger ghs.google.com.
    
  • (DNSの変更が反映されるまで)しばらく待つ。キャッシュもあるので1,2時間ぐらいかな

Bloggerでの設定

  • http://www.blogger.com/home からメニューの「設定」を選択
  • ブログのアドレスの部分で下記のように設定する。
  • blogger-domain

2013年8月24日土曜日

Mac OSX Mountain LionがApp Storeからダウンロードできない

症状

Mac OSX Mountain LionをAppStoreで購入しダウンロードしようとしても10.4MBまでダウンロードしたあたりで「アプリケーションをダウンロードできませんでした。」というエラーのダイアログが表示される。
  • OSを再起動してもダメ
  • Disk自体は100GB空きがある
  • インターネット接続は問題なし
  • 他のアプリケーションはダウンロード&インストールできる(サイズが大きいアプリがダメ?0

解決策

DNSの設定で 8.8.8.8 を設定していたが、これをISPのDNSサーバに変更したら無事ダウンロードできた!ただし原因はよくわからない。
Mac OS X Mountain Lionマスターブック (Mac Fan Books)
小山 香織
マイナビ
売り上げランキング: 26,482

Bloggerに移行してみた

はてなブログはサイドバーにリンクが貼れないので諦めた... Markdownで書けるのはすごい良かったんだけどね。