Parce que, je voulais voir où ça mènerai, bah ça mène là (pour Linux uniquement) :
import shlex
import tempfile
from ctypes import CDLL, py_object
from functools import wraps
from inspect import signature
from subprocess import PIPE, run
def compile(c_str) -> CDLL:
with tempfile.TemporaryDirectory() as tmpdir:
with open(f"{tmpdir}/tmp.c", "w", encoding="UTF-8") as f:
f.write(c_str)
flags = shlex.split(run(["python3-config", "--cflags", "--ldflags"], encoding="UTF-8", stdout=PIPE).stdout)
run(["cc", "-shared", "-fPIC", "-xc"] + flags + [f"-o{tmpdir}/tmp.so", f"{tmpdir}/tmp.c"], check=True)
return CDLL(f"{tmpdir}/tmp.so")
def c(fct):
parameters = signature(fct).parameters
c_args = ", ".join([f"PyObject *{name}" for name in parameters.keys()])
lib = compile(FR"""
#include <stdio.h>
#include <Python.h>
PyObject *the_function({c_args}) {{
{fct.__doc__}
}}
""")
lib.the_function.argtypes = [py_object] * len(parameters)
lib.the_function.restype = py_object
@wraps(fct)
def call_c(*args):
return lib.the_function(*args)
return call_c
@c
def cprint(pyobject):
r"""
Py_ssize_t size;
const char *str;
PyGILState_STATE state = PyGILState_Ensure();
if (PyUnicode_CheckExact(pyobject)) {
str = PyUnicode_AsUTF8AndSize(pyobject, &size);
write(1, str, size);
write(1, "\n", 1);
}
else {
PyObject *repr = PyObject_Repr(pyobject);
printf("%s\n", PyUnicode_AsUTF8(repr));
}
PyGILState_Release(state);
return Py_None;
"""
@c
def fib(n):
"""
long m = PyLong_AsLong(n);
long a = 1;
long b = 1;
PyGILState_STATE state = PyGILState_Ensure();
for (int i = 0; i < m; i++) {
b = a + b;
a = b - a;
}
n = PyLong_FromLong(a);
PyGILState_Release(state);
return n;
"""
def main():
cprint([fib(i) for i in range(40)])
if __name__ == "__main__":
main()
Bon ça marche, ça m’amuse, c’est tout.
OK pour ceux qui veulent vraiment parler perfs, même si c’était pas mon but (promis) :
$ pyperf timeit -s 'import inline_c' 'inline_c.py_fib(40)'
.....................
Mean +- std dev: 993 ns +- 70 ns
$ pyperf timeit -s 'import inline_c' 'inline_c.c_fib(40)'
.....................
Mean +- std dev: 257 ns +- 6 ns
mais on perd la magie des int
de Python, très vite le long
ne suffira pas a contenir le résultat de fib, les deux implèms ne sont donc pas comparables, l’une est rapide, l’autre est juste, meh, arrêtons de parler perfs.
Qui pour implémenter @asm
?