nikkie-ftnextの日記

イベントレポートや読書メモを発信

Pythonコードのベンチマークが測れるライブラリ pyperf をお試し 〜Union型について計測〜

本日は小ネタ更新です

目次

pyperfを知る

先日PEP 604(PythonでUnion型を|で表せる)のメーリングリストを覗きました。

その中で、日本人コミッターの稲田さんがパフォーマンスについて述べていました。
https://mail.python.org/archives/list/python-ideas@python.org/message/HHIAHG7MLOL2DP5NXK5OCWC5ENKWOAEW/

$ python3 -m pyperf timeit -s 'from collections.abc import Iterable; x=[]' -- 'isinstance(x, Iterable)'

これがきっかけでpyperfというライブラリを知りました。

pyperf - Toolkit to run Python benchmarks

すごい偶然で、本日3/6付けで最新の2.6.3がリリースされています!🎉

稲田さんの例はpyperf timeitコマンドを使っています1
https://github.com/psf/pyperf/tree/2.6.3?tab=readme-ov-file#usage

書式は以下

pyperf timeit stmt

ベンチマークを実行したいコード(文)を書きます。
上の例ではisinstance関数の実行ですね。

-s--setupオプション。
ベンチマーク対象コードの前に実行したいコードを書きます。
上の例ではIterableのimportと変数xの宣言の2つをまとめてですね

他のオプションはpyperf timeit --helpで確認できます。

PEP 604のメーリングリストに見た pyperf は何をやっているのか

ABC has extension module for speedup, but isinstance([], Iterable) is 4x slower than isinstance([], (str, list).

PythonのABC(抽象基底クラス)について、速度を上げる拡張モジュールを持っているが、それでもisinstance([], collections.abc.Iterable)isinstance([], (str, list))よりも遅いことを示しています。

M1 Macで再現実験しました。

% sw_vers
ProductName:    macOS
ProductVersion: 12.6.6
BuildVersion:   21G646
% python3 -m pyperf timeit -s 'from collections.abc import Iterable; x=[]' -- 'isinstance(x, Iterable)'
.....................
Mean +- std dev: 123 ns +- 1 ns

% python3 -m pyperf timeit -s 'x=[]; T=(str, list)' -- 'isinstance(x, T)'
.....................
Mean +- std dev: 30.5 ns +- 1.2 ns
  • 稲田さんが実行したPython 3.7の結果と比べると、どちらも早くなってる
    • Faster CPython2の結果!!(と理解)
  • 4倍遅いは健在

稲田さんが表明している懸念、int | strのような書き方のパフォーマンス(先日のエントリ参照)を確認してみます。

% python3 -m pyperf timeit -s 'x=[]; T=str | list' -- 'isinstance(x, T)'
.....................
Mean +- std dev: 31.3 ns +- 0.6 ns

おー、T=(str, list)と同様の速さ
collections.abc.Iterableとは違いますね。

typing.Unionと比較してみます。

% python3 -m pyperf timeit -s 'from typing import Union; x=[]; T=Union[str, list]' -- 'isinstance(x, T)'
.....................
Mean +- std dev: 149 ns +- 2 ns

typing.Unionは遅いのか〜(collections.abc.Iterableと同程度)。
|言語本体でサポートしているから高速ってことなのかな(実力が足りないので今はこの程度の理解。悔しい)

ひとまず宿題が果たせたぞ!🙌

終わりに

pyperf timeitPythonコード片のベンチマークを測れます!
Union型まわりのベンチマークを測ってみました。


  1. 余談ですが、標準ライブラリにtimeitがあります。
  2. https://docs.python.org/ja/3/whatsnew/3.11.html#whatsnew311-faster-cpython 日本語だと「CPython高速化計画」