In [8]:
import ctypes
import math as m
from ctypes.util import find_library
In [9]:
# Windows .dll
# Linux .so
In [11]:
libm = ctypes.CDLL(find_library('m'))
csin = libm.sin
csin.restype = ctypes.c_double
x = ctypes.c_double(1.0)
csin(x), m.sin(1.0)
Out[11]:
(0.8414709848078965, 0.8414709848078965)
In [13]:
x_c = ctypes.c_double(1.0)
x_py = 1.0
%timeit csin(x_c)
%timeit m.sin(x_py)
322 ns ± 2.69 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
131 ns ± 0.565 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [15]:
from time import ctime
libc = ctypes.CDLL(find_library('c'))
ctime(libc.time(None))
Out[15]:
'Mon Dec 14 13:25:33 2020'
In [16]:
%load_ext cython
In [19]:
from cymodule.pymodule import golden_ratio as cythonize_golden_ratio
%timeit cythonize_golden_ratio(1_000_000)

from pymodule import golden_ratio as golden_ratio
%timeit golden_ratio(1_000_000)
59.3 ms ± 187 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
62 ms ± 3.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [20]:
%%cython --annotate

def f(x):
    cdef double y = 1.0
    cdef double z = x + y
    return z

print(f(2))
3.0
Out[20]:
Cython: _cython_magic_a25cc206250de381ca3f21379ccb32a8.pyx

Generated by Cython 0.29.15

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 1: 
+2: def f(x):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_a25cc206250de381ca3f21379ccb32a8_1f(PyObject *__pyx_self, PyObject *__pyx_v_x); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_a25cc206250de381ca3f21379ccb32a8_1f = {"f", (PyCFunction)__pyx_pw_46_cython_magic_a25cc206250de381ca3f21379ccb32a8_1f, METH_O, 0};
static PyObject *__pyx_pw_46_cython_magic_a25cc206250de381ca3f21379ccb32a8_1f(PyObject *__pyx_self, PyObject *__pyx_v_x) {
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("f (wrapper)", 0);
  __pyx_r = __pyx_pf_46_cython_magic_a25cc206250de381ca3f21379ccb32a8_f(__pyx_self, ((PyObject *)__pyx_v_x));

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_a25cc206250de381ca3f21379ccb32a8_f(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_x) {
  double __pyx_v_y;
  double __pyx_v_z;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("f", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_AddTraceback("_cython_magic_a25cc206250de381ca3f21379ccb32a8.f", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple_ = PyTuple_Pack(3, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_z); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple_);
  __Pyx_GIVEREF(__pyx_tuple_);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_a25cc206250de381ca3f21379ccb32a8_1f, NULL, __pyx_n_s_cython_magic_a25cc206250de381ca); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_f, __pyx_t_1) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(1, 0, 3, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_jovyan_cache_ipython_cytho, __pyx_n_s_f, 2, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) __PYX_ERR(0, 2, __pyx_L1_error)
+3:     cdef double y = 1.0
  __pyx_v_y = 1.0;
+4:     cdef double z = x + y
  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = PyNumber_Add(__pyx_v_x, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 4, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_v_z = __pyx_t_3;
+5:     return z
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_2 = PyFloat_FromDouble(__pyx_v_z); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_r = __pyx_t_2;
  __pyx_t_2 = 0;
  goto __pyx_L0;
 6: 
+7: print(f(2))
  __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_f); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 7, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 7, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 7, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
In [23]:
! cythonize -3 -a -i cy_golden_ratio.pyx
Compiling /home/jovyan/work/cy_golden_ratio.pyx because it changed.
[1/1] Cythonizing /home/jovyan/work/cy_golden_ratio.pyx
running build_ext
building 'cy_golden_ratio' extension
creating /home/jovyan/work/tmp9biydcrw/home
creating /home/jovyan/work/tmp9biydcrw/home/jovyan
creating /home/jovyan/work/tmp9biydcrw/home/jovyan/work
gcc -pthread -B /opt/conda/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/opt/conda/include/python3.7m -c /home/jovyan/work/cy_golden_ratio.cpp -o /home/jovyan/work/tmp9biydcrw/home/jovyan/work/cy_golden_ratio.o
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
g++ -pthread -shared -B /opt/conda/compiler_compat -L/opt/conda/lib -Wl,-rpath=/opt/conda/lib -Wl,--no-as-needed -Wl,--sysroot=/ /home/jovyan/work/tmp9biydcrw/home/jovyan/work/cy_golden_ratio.o -o /home/jovyan/work/cy_golden_ratio.cpython-37m-x86_64-linux-gnu.so
In [22]:
from cy_golden_ratio import golden_ratio as cy_golden_ratio
%timeit cy_golden_ratio(1_000_000)
20.1 ms ± 529 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [24]:
from cy_golden_ratio import golden_ratio as cy_golden_ratio
%timeit cy_golden_ratio(1_000_000)
19.7 ms ± 805 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [25]:
# f2py
In [26]:
# SWIG
In [28]:
# C++: Boost::Python
In [29]:
# Rust + PyO3
In [ ]:
 
In [30]:
# SciPy lowlevel callable
In [ ]: