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だとさらに大変になる

0 件のコメント: