04 - Cython שילוב של C עם Python לה
Download
Report
Transcript 04 - Cython שילוב של C עם Python לה
שיאון שחורי
MilOSS-il 2012
מוטיבציה
python זה קל ו Cזה מהיר .למה לא לשלב?
יש כבר קוד קיים ב .Cאנחנו רוצים להשתמש
בו ,ולבסס מעליו קוד חדש ב python
מסקנה :צריך ממשק (דו כיווני) בין pythonל C
פתרונות ידועים (לי) :שימוש בתהליכים נפרדים,
C/Python API ,ctypesאו cython
פתרונות (תהליכים)
תהליכים שונים
אחד כתוב ב ,Cהשני ב python
העברת מידע באמצעות ,socket( IOקבצים וכו')
מה קיבלנו?
לא צריך להכיר טכנולוגיה חדשה
צריך לנהל תהליך Cמלא
לא יעיל
מסורבל
צריך להגדיר ממשקים בין התהליכים
פתרונות ()ctypes
יצירת dllושימוש ב ctypes
כתיבת dynamic libraryב C
טעינה של הספרייה באמצעות ctypes
קריאה לפונקציות שנכתבו ב C
פתרונות ()ctypes
מה קיבלנו?
תהליך בודד
יעיל
קל
הגדרות כפולות (ולאו דווקא תואמות)
קישוריות חד כיוונית (אי אפשר לקרוא לקוד python
מתוך Cבקלות)
פתרונות ()C/Python API
שימוש ב C/Python API
קידוד קוד ב Cתוך קריאה לפונקציות מתוך Python.h
בניית extensionבאמצעות distutils
שימוש מתוך פייתון באמצעות import
מה קיבלנו?
תהליך בודד
יעיל
הגדרת טיפוסים בודדת
קישוריות דו כיווניות
קידוד מסורבל (למשל ,שימוש באובייקטים פייתונים מתוך
)C
פתרונות ()Cython
שימוש ב Cython
מבוסס pyrex
כתיבת קבצי :.pyxקבצי ( pythonפחות או יותר) עם
פקודות מיוחדות
בניית extensionבאמצעות distutils
שימוש מתוך פייתון באמצעות import
מה קיבלנו?
תהליך בודד
יעיל
הגדרת טיפוסים בודדת ( כמעט )
קישוריות דו כיווניות
קידוד נוח
בסיסיCython
#include <stdio.h>
bla.h
inline int my_func(int x)
{
printf(“my func %d\n”, x);
return 0;
}
cdef extern from “bla.h”:
int my_func(int)
bla.pyx
def pymy_func(x):
return my_func(x)
import bla
print bla.pymy_func(10)
main.py
Distutils setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup.py
setup(cmdclass={'build_ext': build_ext},
ext_modules=[Extension(“bla", ['bla.pyx'])])
$ python setup.py build_ext --inplace
בנייה
running build_ext
cythoning bla.pyx to bla.c
building 'bla' extension
gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall Wstrict-prototypes -fPIC -I/usr/include/python2.6 -c bla.c -o
build/temp.linux-i686-2.6/bla.o
gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linuxi686-2.6/bla.o -o /mnt/filer_home/users/t_sion/bla.so
דוגמה :קידוד פשוט
הבעיה :יש מערך גדול של בתים ,ורוצים לקודד
אותו עם הקוד הפשוט הבא :כל בית מוחלף
בשני בתים :הבית המקורי וה notשלו
מימוש פייתוני
import array
pyencode.py
lookup = {}
for i in range(256):
lookup[chr(i)] = chr(i) + chr(i ^ 0xFF)
def encode(arr):
out = array.array('c', '\x00' * len(arr) * 2)
for i in xrange(len(arr)):
data = lookup[arr[i]]
out[2*i] = data[0]
out[2*i + 1] = data[1]
return out
המשך- מימוש פייתוני
In [10]: s = array.array('c', '\x01\xf3\x34\x45' * (10 ** 6))
In [11]: import pyencode
In [12]: %timeit -n 3 pyencode.encode(s)
3 loops, best of 3: 2.84 s per loop
פשוטcython מימוש
למודולcython רק מקומפל עם, אותו קוד
cyencode_simple
In [13]: import cyencode_simple
In [14]: %timeit -n 3 cyencode_simple.encode(s)
3 loops, best of 3: 1.62 s per loop
מתקדםcython מימוש
import array
cdef unsigned short lookup[256]
cdef unsigned char *_ptr
for i in range(256):
_ptr = <unsigned char*>(&lookup[i])
_ptr[0] = <int>i
_ptr[1] = <int>(i ^ 0xFF)
cyencode.py
def encode(arr):
cdef int i
cdef unsigned char *in_ptr, *out_ptr, *p
in_ptr = <unsigned char*><unsigned int>(arr.buffer_info()[0])
out = array.array('c', '\x00' * len(arr) * 2)
out_ptr = <unsigned char*><unsigned int>(out.buffer_info()[0])
for i in range(len(arr)):
p = <unsigned char*>(&lookup[<int>in_ptr[i]])
out_ptr[2*i] = p[0]
out_ptr[2*i + 1] = p[1]
return out
המשך- מתקדםcython מימוש
In [15]: import cyencode
In [16]: %timeit -n 3 cyencode.encode(s)
3 loops, best of 3: 26.8 ms per loop
C מתקדם – הצצה לקודcython מימוש
for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_4; __pyx_t_6+=1) {
__pyx_v_i = __pyx_t_6;
cyencode.c
/* "cyencode.pyx":17
*
p = <unsigned char*>(&lookup[<int>in_ptr[i]]) # <<<<<<<
*/
__pyx_v_p = ((unsigned char *)(&(__pyx_v_8cyencode_lookup[
((int)(__pyx_v_in_ptr[__pyx_v_i]))])));
/* "cyencode.pyx":18
*
out_ptr[2*i] = p[0]
# <<<<<<<
*/
(__pyx_v_out_ptr[(2 * __pyx_v_i)]) = (__pyx_v_p[0]);
/* "cyencode.pyx":19
*
out_ptr[2*i + 1] = p[1]
# <<<<<<<
*/
(__pyx_v_out_ptr[((2 * __pyx_v_i) + 1)]) = (__pyx_v_p[1]);
}
Pitfalls
GIL
Reference counting
cdef functions טיפול בשגיאות ב
פיצ'רים נוספים
def,cdef,cpdef
– namespaces איך לתת שמות זהים בפייתון
וב C
קבצי .pxd
cinit ו dealloc
אינטגרציה עם numpy
מידע נוסף
http://docs.cython.org :cython תיעוד
טובtutorial כולל
sion.schori@gmail : במייל שלי