mercredi 25 mars 2015

Python dictionaries vs C++ std:unordered_map (cython) vs cythonized python dict


I was trying to measure the performance between python dictionaries, cythonized python dictionaries and cythonized cpp std::unordered_map doing only a init procedure. If the cythonized cpp code is compiled I thought it should be faster than the pure python version. I did a test using 4 different scenario/notation options:



  • Cython CPP code using std::unordered_map and Cython book notation (defining a pair and using insert method)

  • Cython CPP code using std::unordered_map and python notation (map[key] = value)

  • Cython code (typed code) using python dictionaries (map[key] = value)

  • Pure python code


I was expecting see how cython code outperforms pure python code, but surprisingly the pure python code is much more faster than cython versions. How can we explain that?... am I missing something?. I'm using Cython 0.22, python-3.4 and g++-4.8.


I got this exec time (seconds) using timeit:



  • Cython CPP book notation -> 60.531494464725256

  • Cython CPP python notation -> 59.7511575082317

  • Cython python notation -> 19.937705864198506

  • Pure python -> 18.230739895720035


Code is here and you can use it:



cython -a map_example.pyx
python3 setup_map.py build_ext --inplace
python3 use_map_example.py


map_example.pyx



from libcpp.unordered_map cimport unordered_map
from libcpp.pair cimport pair

cpdef int example_cpp_book_notation(int limit):
cdef unordered_map[int, int] mapa
cdef pair[int, int] entry

cdef int i

for i in range(limit):
entry.first = i
entry.second = i
mapa.insert(entry)
return 0

cpdef int example_cpp_python_notation(int limit):
cdef unordered_map[int, int] mapa
cdef pair[int, int] entry

cdef int i

for i in range(limit):
mapa[i] = i

return 0


cpdef int example_ctyped_notation(int limit):
mapa = {}
cdef int i
for i in range(limit):
mapa[i] = i
return 0


setup_map.py



from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext

import os

os.environ["CC"] = "g++"
os.environ["CXX"] = "g++"


modules = [Extension("MapExample",
["map_example.pyx"],
language = "c++",
extra_compile_args=["-std=c++11"],
extra_link_args=["-std=c++11"])]

setup(name="MapExample",
cmdclass={"build_ext": build_ext},
ext_modules=modules)


use_map_example.py



import map_example

C_MAXV = 100000000
C_NUMBER = 10

def cython_cpp_book_notation():
x = 1
while(x<C_MAXV):
map_example.example_cpp_book_notation(x)
x *= 10

def cython_cpp_python_notation():
x = 1
while(x<C_MAXV):
map_example.example_cpp_python_notation(x)
x *= 10

def cython_ctyped_notation():
x = 1
while(x<C_MAXV):
map_example.example_ctyped_notation(x)
x *= 10


def pure_python():
x = 1
while(x<C_MAXV):
map_a = {}
for i in range(x):
map_a[i] = i
x *= 10
return 0


if __name__ == '__main__':
import timeit

print("Cython CPP book notation")
print(timeit.timeit("cython_cpp_book_notation()", setup="from __main__ import cython_cpp_book_notation", number=C_NUMBER))


print("Cython CPP python notation")
print(timeit.timeit("cython_cpp_python_notation()", setup="from __main__ import cython_cpp_python_notation", number=C_NUMBER))


print("Cython python notation")
print(timeit.timeit("cython_ctyped_notation()", setup="from __main__ import cython_ctyped_notation", number=C_NUMBER))

print("Pure python")
print(timeit.timeit("pure_python()", setup="from __main__ import pure_python", number=C_NUMBER))



Aucun commentaire:

Enregistrer un commentaire