私はオーバーヘッドに関心がありました。だから、多かれ少なかれ機能する2つの関数nop
とstarnop
をエクスポートする最小限のC拡張を書きました。彼らは彼らの入力を通過する(2つの関連機能は、残りはちょうど退屈なボイラープレートコードである上部に右である):関数呼び出しのオーバーヘッド - Pythonの組み込み関数が組み込み関数より速いのはなぜですか?
amanmodule.c:
#include <Python.h>
static PyObject* aman_nop(PyObject *self, PyObject *args)
{
PyObject *obj;
if (!PyArg_UnpackTuple(args, "arg", 1, 1, &obj))
return NULL;
Py_INCREF(obj);
return obj;
}
static PyObject* aman_starnop(PyObject *self, PyObject *args)
{
Py_INCREF(args);
return args;
}
static PyMethodDef AmanMethods[] = {
{"nop", (PyCFunction)aman_nop, METH_VARARGS,
PyDoc_STR("nop(arg) -> arg\n\nReturn arg unchanged.")},
{"starnop", (PyCFunction)aman_starnop, METH_VARARGS,
PyDoc_STR("starnop(*args) -> args\n\nReturn tuple of args unchanged")},
{NULL, NULL}
};
static struct PyModuleDef amanmodule = {
PyModuleDef_HEAD_INIT,
"aman",
"aman - a module about nothing.\n\n"
"Provides functions 'nop' and 'starnop' which do nothing:\n"
"nop(arg) -> arg; starnop(*args) -> args\n",
-1,
AmanMethods
};
PyMODINIT_FUNC
PyInit_aman(void)
{
return PyModule_Create(&amanmodule);
}
setup.py:
from setuptools import setup, extension
setup(name='aman', version='1.0',
ext_modules=[extension.Extension('aman', ['amanmodule.c'])],
author='n.n.',
description="""aman - a module about nothing
Provides functions 'nop' and 'starnop' which do nothing:
nop(arg) -> arg; starnop(*args) -> args
""",
license='public domain',
keywords='nop pass-through identity')
import numpy as np
from aman import nop, starnop
from timeit import timeit
def mnsd(x): return '{:8.6f} \u00b1 {:8.6f} \u00b5s'.format(np.mean(x), np.std(x))
def pnp(x): x
globals={}
for globals['nop'] in (int, bool, (0).__add__, hash, starnop, nop, pnp, lambda x: x):
print('{:60s}'.format(repr(globals['nop'])),
mnsd([timeit('nop(1)', globals=globals) for i in range(10)]),
' ',
mnsd([timeit('nop(True)',globals=globals) for i in range(10)]))
:
次に、私は純粋なPythonの実装とも何も次に何組み込みコマンドのカップルに対してそれらを時間を計ります3210
最初の質問私は方法論的に遅れた何かをやっていないのですか? 1,000,000通話ごとの10個のブロックの
結果:
<class 'int'> 0.099754 ± 0.003917 µs 0.103933 ± 0.000585 µs
<class 'bool'> 0.097711 ± 0.000661 µs 0.094412 ± 0.000612 µs
<method-wrapper '__add__' of int object at 0x8c7000> 0.065146 ± 0.000728 µs 0.064976 ± 0.000605 µs
<built-in function hash> 0.039546 ± 0.000671 µs 0.039566 ± 0.000452 µs
<built-in function starnop> 0.056490 ± 0.000873 µs 0.056234 ± 0.000181 µs
<built-in function nop> 0.060094 ± 0.000799 µs 0.059959 ± 0.000170 µs
<function pnp at 0x7fa31c0512f0> 0.090452 ± 0.001077 µs 0.098479 ± 0.003314 µs
<function <lambda> at 0x7fa31c051378> 0.086387 ± 0.000817 µs 0.086536 ± 0.000714 µs
今私の実際の質問:私のnopはCで書かれており、何もしない場合であっても(starnop
もその引数を解析しません)組み込みhash
機能一貫して高速です。私はintがPythonで独自のハッシュ値であることを知っていますので、hash
もここではノップですが、それは私のノップ以上のものではないので、なぜスピードの違いですか?
更新:完全に忘れてしまった:私はかなり標準的なx86_64マシン、linux gcc4.8.5です。拡張子はpython3 setup.py install --user
を使用してインストールします。
どのようにあなたのCコードをコンパイルしていますか?あなたはこの重要な情報を私たちに語っていません。また、Pythonはどのようにコンパイルされていますか?あなたのコードにない最適化がPythonで有効になっていますか? – Sebivor
@Sebivorはセットアップスクリプトを呼び出すだけです: 'python3 setup.py install --user'。私は、あなたが明示的に指定しない限り、Python自体がコンパイルされたのと同じコンパイラ設定を使用すると常に考えていました。私は質問を更新します。 –
...と私が尋ねた他の質問への答え?それらも持っていますか?そうでなければ、あなたはこの質問をするのに十分な研究をしていません。 – Sebivor