Skip to content

Commit c2df8df

Browse files
committed
create ctypes class type only once
1 parent f8eb626 commit c2df8df

File tree

1 file changed

+45
-19
lines changed

1 file changed

+45
-19
lines changed

pycon2017_cffi.ipynb

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,10 +2086,8 @@
20862086
},
20872087
{
20882088
"cell_type": "code",
2089-
"execution_count": 16,
2090-
"metadata": {
2091-
"collapsed": true
2092-
},
2089+
"execution_count": 32,
2090+
"metadata": {},
20932091
"outputs": [],
20942092
"source": [
20952093
"#ctypes\n",
@@ -2101,18 +2099,22 @@
21012099
" ('height', ctypes.c_int),\n",
21022100
" ('data', ctypes.POINTER(ctypes.c_uint8)), # HUH?\n",
21032101
" ]\n",
2104-
"\n",
2102+
" array_cache = {}\n",
21052103
" def __init__(self, width, height):\n",
21062104
" self.width = width\n",
21072105
" self.height = height\n",
2108-
" # Note this creates a class for each width*height value\n",
2109-
" # but will keep the img.data alive in the interpreter\n",
2110-
" self.data = (ctypes.c_uint8 * (width * height))() # !!!!!!\n",
2106+
" # Create a class type to hold the data.\n",
2107+
" # Since this creates a type, cache it for reuse rather\n",
2108+
" # than create a new one each time\n",
2109+
" if width*height not in self.array_cache:\n",
2110+
" self.array_cache[width*height] = ctypes.c_uint8 * (width * height)\n",
2111+
" # Note this keeps the img.data alive in the interpreter\n",
2112+
" self.data = self.array_cache[width*height]() # !!!!!!\n",
21112113
"\n",
21122114
" def asmemoryview(self):\n",
21132115
" # There must be a better way, but this code will not\n",
21142116
" # be timed, so explicit trumps implicit\n",
2115-
" ret = (ctypes.c_uint8 * (width * height))()\n",
2117+
" ret = self.data = self.array_cache[width*height]()\n",
21162118
" for i in range(width*height):\n",
21172119
" ret[i] = self.data[i]\n",
21182120
" return memoryview(ret)\n",
@@ -2128,7 +2130,8 @@
21282130
"create_fractal_ctypes.argtypes = [CtypesImg, ctypes.c_int]\n",
21292131
"\n",
21302132
"mandel_ctypes = cdll.mandel\n",
2131-
"mandel_ctypes.argtypes = [ctypes.c_float, ctypes.c_float, ctypes.c_int, ctypes.POINTER(ctypes.c_uint8)]"
2133+
"mandel_ctypes.argtypes = [ctypes.c_float, ctypes.c_float, ctypes.c_int, \n",
2134+
" ctypes.POINTER(ctypes.c_uint8)]"
21322135
]
21332136
},
21342137
{
@@ -2144,15 +2147,15 @@
21442147
},
21452148
{
21462149
"cell_type": "code",
2147-
"execution_count": 17,
2150+
"execution_count": 33,
21482151
"metadata": {},
21492152
"outputs": [
21502153
{
21512154
"name": "stdout",
21522155
"output_type": "stream",
21532156
"text": [
2154-
"ctypes calling create_fractal required 203.95 millisecs\n",
2155-
"ctypes calling mandel required 2604.29 millisecs\n"
2157+
"ctypes calling create_fractal required 197.33 millisecs\n",
2158+
"ctypes calling mandel required 2463.65 millisecs\n"
21562159
]
21572160
}
21582161
],
@@ -4592,7 +4595,8 @@
45924595
" unsigned char * data\n",
45934596
" \n",
45944597
" int create_fractal(cImg img, int iters);\n",
4595-
" int mandel(float real, float imag, int max_iters, unsigned char * val);\n",
4598+
" int mandel(float real, float imag, int max_iters,\n",
4599+
" unsigned char * val);\n",
45964600
" \n",
45974601
"def cython_create_fractal(pyimg, iters):\n",
45984602
" cdef cImg cimg\n",
@@ -4606,7 +4610,8 @@
46064610
" return create_fractal(cimg, citers)\n",
46074611
"\n",
46084612
"\n",
4609-
"cpdef int cython_mandel(float real, float imag, int max_iters, unsigned char[::1] val):\n",
4613+
"cpdef int cython_mandel(float real, float imag, int max_iters,\n",
4614+
" unsigned char[::1] val):\n",
46104615
" return mandel(real, imag, max_iters, &val[0])"
46114616
]
46124617
},
@@ -5463,7 +5468,9 @@
54635468
{
54645469
"cell_type": "code",
54655470
"execution_count": 27,
5466-
"metadata": {},
5471+
"metadata": {
5472+
"scrolled": true
5473+
},
54675474
"outputs": [
54685475
{
54695476
"name": "stdout",
@@ -5479,7 +5486,8 @@
54795486
}
54805487
],
54815488
"source": [
5482-
"# Now let's try and work out who is the good, who the bad, and who the ugly\n",
5489+
"# Now let's try and work out who is the good, who the bad, \n",
5490+
"# and who the ugly\n",
54835491
"import pprint\n",
54845492
"pprint.pprint([[' ', 'CreateFractal in Python', 'CreateFractal in C'],\n",
54855493
" ['Python', '{:13.2f} millisecs'.format(1000*pure_python), '{:18s}'.format('')],\n",
@@ -5500,16 +5508,34 @@
55005508
" - What happens when the C code changes?\n",
55015509
"* Compiler dependency\n",
55025510
" - ctypes needs none, Cython requires one, CFFI can go either way\n",
5503-
"* Suseptability to bugs (object lifetimes, signature mismatches)\n",
5511+
"* Susceptability to bugs (object lifetimes, signature mismatches)\n",
55045512
" - All use a minilanguage for interfacing, only CFFI's is standard C\n",
55055513
" - Cython will handle most transformations automatically\n",
55065514
" - CFFI can be tricky for C-level pointers\n",
55075515
"* Speed and productivity\n",
55085516
" - Cython is heavily optimized, tightly integrated to the C-API\n",
55095517
" - If the headers are pure C, CFFI should be simple\n",
55105518
" - Projects exist to generate wrappers for all three\n",
5511-
"* Which technology is actively maintained (ctypes went into the stdlib to die?)\n",
5519+
"* Which technology is actively maintained (ctypes went into the stdlib to die?)"
5520+
]
5521+
},
5522+
{
5523+
"cell_type": "markdown",
5524+
"metadata": {},
5525+
"source": [
5526+
" --- \n",
5527+
" --- \n",
5528+
" --- \n",
5529+
" --- \n",
5530+
" \n",
55125531
"\n",
5532+
"\n"
5533+
]
5534+
},
5535+
{
5536+
"cell_type": "markdown",
5537+
"metadata": {},
5538+
"source": [
55135539
"And now the pop-quiz. If we run the pure python version in PyPy what time will we get?:\n",
55145540
"\n",
55155541
"* Around a 2X speed up\n",

0 commit comments

Comments
 (0)