SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

EuroPythonレポート

EuroPython 2018参加レポート(2)~Pythonによるサウンド生成、C APIのエミュレート、Decoratorの分類

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

PyPy(cpyext)におけるC APIやCオブジェクトモデルのエミュレート方法

Adventures in compatibility: emulating CPython's C API in PyPy
Adventures in compatibility: emulating CPython's C API in PyPy
  • タイトル:Adventures in compatibility: emulating CPython's C API in PyPy
  • 発表者:Ronan Lamy
  • セッション動画

 PyPyはRPythonツールチェインを使って実装されたPython処理系です。Pythonの仕様に準拠していながら、CPythonよりも高速に動作するとされています。PyPyにおいてC言語で書かれたプログラムを呼び出す際には、CFFIが最も簡潔で効率的な方法ですが、NumPyのようにCPythonのC APIを利用しているC拡張モジュールとして多くの優れたライブラリが存在します。

 以前はCPythonを別プロセスで起動して、TCP経由でRPCコマンドをやりとりする必要がありました[3]。しかし現在はcpyextというモジュールがC APIをエミュレートすることで、CPythonを起動することなくC拡張モジュールを実行できます。これをどのように実現したのかについて、PyPyのコア開発者によって解説されました。

PyPyのアーキテクチャ

 本題に入る前にPyPyがCPythonよりも速いとされている理由について解説がありました。PyPyのパフォーマンスが優れている理由はいくつかありますが、最も寄与しているものはJITコンパイラによるものです。PyPyのアーキテクチャをみてみましょう。

PyPyのアーキテクチャ
PyPyのアーキテクチャ

 CPythonでは生成したバイトコードをただバイトコードインタープリターが処理しますが、PyPyではバイトコードインタプリターが処理をしながらランタイム情報をトレースします。具体的にはソースコードのどの部分が何回実行されたのかといった情報や、実行時の型情報を解析しています[4]。そこで得たランタイム情報をもとに最適化されたマシンコードを生成しています。JITのコンパイラは実装が難しく複雑になりますが、RPythonツールチェインの中にはJITコンパイラの実装をサポートするためのトレースオプティマイザーが組み込まれています。詳細はRPythonのドキュメントを参照してください。

cpyextによるCPythonのC APIのエミュレート

 PyPyにはC APIをエミュレートするためのモジュールとしてcpyextが存在します。その中身を見ると次のようになっています。

# 参照: https://bitbucket.org/pypy/pypy/src/45c392a241f5d7d11a925beeb3e7e3b3bb342a03/pypy/module/cpyext/dictobject.py
@cpython_api([PyObject], Py_ssize_t, error=-1)
def PyDict_Size(space, w_obj):
    return space.len_w(w_obj)

 このコードはC APIの処理がPythonで再実装されていることを示しています。cpython_apiデコレーターによりC APIとPythonの関数が紐付けられます。これはどのようにC拡張から呼び出されるのでしょうか?

 C拡張モジュールは、呼び出したいCの関数をPython.h(Cヘッダーファイル)の情報をもとに特定します。PyPyでは独自のPython.hを内部で用意していて、C拡張はそのヘッダーファイルをもとにコンパイルされます。実行時にはPyPyが提供しているCのインターフェイスを経由してPyPyインタープリター上にもオブジェクトが生成されます。そしてC API呼び出しにフックして先程の例に示したPythonで記述された関数が呼び出されます。

 そうはいっても、もともとC言語で実装されたAPIを、RPythonで再実装するのは当然簡単なことではありません。両者は全然違う言語ですので、多くの違いがあります[4]。文字数の都合上すべてをここで解説することはできませんが、ガベージコレクション(以下、GC)のアルゴリズムの違いについてここでは触れようかと思います。

 CPythonはご存知の通り参照カウントを計算していて、あるオブジェクトの参照カウントが0になったタイミングでメモリからすぐに開放されます[5]。しかしPyPyでは参照カウントを管理せずincminimark[6]とよばれるGCが走るタイミングに依存してオブジェクトがメモリから開放されます。

 そこでPyPyではC拡張が扱うCオブジェクトと、PyPyインタープリター上に存在するオブジェクトをセットで管理し、参照カウントが0もしくはPyPyのオブジェクトが到達不能になりGCによって破棄されたタイミングで同時に破棄しているとのことでした。

余談:Victor StinnerによるC APIの改善提案

 少し余談になりますが、このセッションについて筆者(芝田)がTwitterでつぶやいた時、CPythonのコア開発者であるVictor Stinnerからリプライがありました。

 どうやらCPythonのC APIに課題があるらしく、改善しようと動いているようです。

 当然既存のC拡張が動作するように後方互換を保ったまま、修正する必要があるのですが、詳細は彼の公開したWebサイトにまとまっているようです。かなり長いドキュメントなので筆者はまだ読んでいないのですが、もし興味を持った方はぜひ読んでみてください。

[3] PyPyのブログ記事に記載がありました(「Using CPython extension modules with PyPy, or: PyQt on PyPy」を参照)。

[4] PyPyのドキュメントにも、CPythonとPyPyの違いについてまとまったページがありました(「Differences between PyPy and CPython」を参照)。

[5] 循環参照などにより参照カウントが0にならず、破棄されずに残ってしまったオブジェクトは周期的に実行されるマークアンドスイープのようなGCによって破棄されます。ここで「のような」とぼかしたのは理由があるのですが、石元敦夫氏による詳しい解説があるためそちらをご覧ください。

[6] PyPyはもともとMinimark GCとよばれるGCを実装し、利用していました。その後LuaJITで利用されているIncremental GCのアイデアを取り入れました。これを incminimark(Incremental version of Minimark GC)と呼んでいます。詳細はPyPyのブログ記事を参照してください。

次のページ
Decoratorの分類 A-E

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
EuroPythonレポート連載記事一覧
この記事の著者

芝田 将(株式会社サイバーエージェント)(シバタ マサシ)

 株式会社サイバーエージェント AbemaTV 配信チーム所属。go-prompt 開発者。 共訳書『エキスパートPythonプログラミング改訂2版』。 Webサイト: https://c-bata.link

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

石川 諒(株式会社サイバーエージェント)(イシカワ リョウ)

 株式会社サイバーエージェント AbemaTV iOSエンジニア。主にコード品質や視聴周りの改善を行う本質改善チームに在籍。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/11097 2018/09/28 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング