Python vs Cython vs PyPy.

Moich tendencyjnych eksperymentów ciąg dalszy. Zrezygnowałem z Numpy i jestem pod wrażeniem memoryviews w Cythonie. Poniższe to tak na prawdę test wydajności adresowania tablic jednowymiarowych.

Python:

import sys
import random

def fib(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return a

def showfib(n):
    r = []
    for i in range(n):
        t = fib(random.randint(0,49))
        r.append(t)
        print(t, end=" ")
    print()

if __name__ == '__main__':
    n=int(sys.argv[1])
    showfib(n)

Cython:

#cython: language_level=3, boundscheck=False

import sys
from libc.stdio cimport printf
from libc.stdlib cimport rand, srand
from cython.view cimport array
from time import time

cdef unsigned int fib(int m) nogil:
    cdef unsigned int a, b, i
    a, b = 0, 1
    for i in range(m):
        a, b = b, a + b
    return a

cdef showfib(n):
    cdef r = array(shape=(n,), itemsize=sizeof(unsigned int), format="I")
    cdef unsigned int [:] rv = r

    cdef int i
    cdef unsigned int t
    for i in range(n):
        t = fib(rand()%49)
        rv[i] = t
        printf("%u ", t)
    printf("\n")

if __name__ == '__main__':
    n=int(sys.argv[1])
    srand(int(time()))
    showfib(n)

Python-3.4.2:
$ time python fib.py 300000 > /dev/null
real 0m7.564s
user 0m7.543s
sys 0m0.013s

PyPy3-2.4 (portable):
$ time pypy fib.py 300000 > /dev/null
real 0m1.838s
user 0m1.813s
sys 0m0.020s

Cython-0.21.1:
$ time ./fib 300000 > /dev/null
real 0m0.189s
user 0m0.190s
sys 0m0.000s

Cython vs Python: 40,02 x szybciej.
Pypy vs Python: 4,11 x szybciej.
Cython vs PyPy: 9,72 x szybciej.

Reklamy

Pypy, Cython, mingw-w64, static libpython3.4m.a.

Mój powrót do Pythona po kilkuletniej przerwie skończył się fascynacją. Po pierwsze Pypy – ale to szybkie i całkowicie zgodne z Pythonem! Po drugie Cython (opcja –embed) szok, udało mi się skompilować statyczne binarki skryptu aconv.py dla Linuksa i Windows (walczę jeszcze trochę z kodowaniem konsoli cmd w Windows, bo tu oczywiście są niemałe problemy z 16bit kodowaniem – muszę zrozumieć PyUnicode w Pythonie i Cythonie). Po trzecie: konfiguracja i działanie MSYS z mingw i mingw-w64 – niesamowity toolchain (instalowałem z win-builds), wszystko działa jak na Linuksie, trzeba tylko skonfigurować /c/mingw/msys/1.0/etc/fstab, czyli dodać c:\mingw /mingw, uruchamiać C:\MinGW\msys\1.0>msys.bat a potem konfigurację mingw-w64 (uwaga na kropkę) . /c/mingw/msys/1.0/opt/windows_32/bin/win-builds-switch 32 najlepiej dodać do ~/.bash_profile, ścieżka do gcc z mingw-w64 i bibliotek będzie się sama ustawiać po odpaleniu msys.bat.

Kompilację Pythona 3.4.2 ze statyczną i dynamiczną biblioteką libpython3.4m udostępniłem tutaj). Zbudowany po nałożeniu łatek z repo mingw-w64 i wykonaniu autoreconf-2.68.

W powyższym zipie zmodyfikowałem python/include/pyconfig.h w taki sposób, aby po dodaniu do wywołania gcc opcji -DPy_ENABLE_STATIC -static linkował z libpython3.4m.a, a bez tych opcji z libpython3.4m.dll:

#if defined Py_ENABLE_STATIC
#undef Py_ENABLE_SHARED
#else
#define Py_ENABLE_SHARED 1
#endif

PS: Aby interaktywny interpreter Pythona z tej kompilacji zadziałał, trzeba uruchomić polecenie:
. /c/mingw/msys/1.0/opt/windows_32/bin/win-builds-switch 32 w przeciwnym razie będzie mu brakować bibliotek.