Exercise 11.2
In the practical-python/Ext
directory, you will find a pure-Python script
mandel.py
that creates a PNG file with a plot of the famous
Mandelbrot set. Open that program with IDLE and run it now. You
should get output such as this after about 15-30 seconds:
Wrote mandel.png
16.5698359013 seconds
>>>
As output, the program should create a file practical-python/Ext/mandel.png
. If you go into
the Ext/
directory and double-click on the file, you should see an image such as this:
(a) The Performance Problem
The script that generates the resulting image is entirely written in
Python. However, almost all of the execution time is consumed by the
following function (in mandel.py
)
# Test a given x,y coordinate to see if it's a member of the set
def in_mandelbrot(x0,y0,n):
x = 0
y = 0
while n > 0:
xtemp = x*x - y*y + x0
y = 2*x*y + y0
x = xtemp
n -= 1
if x*x + y*y > 4: return False
return True
Try running the mandel.py
program under the Python profiler.
% python -m cProfile mandel.py
Look at the output and look at the entry for the in_mandelbrot()
function.
(b) Using C Functions
The file Ext/src/mandel.c
contains a C implementation of the in_mandelbrot()
function.
Here is what the code looks like this:
/* mandel.c */
/* Test a given x,y coordinate to see if it's a member of the set */
int
in_mandelbrot(double x0, double y0, int n) {
double x=0,y=0,xtemp;
while (n > 0) {
xtemp = x*x - y*y + x0;
y = 2*x*y + y0;
x = xtemp;
n -= 1;
if (x*x + y*y > 4) return 0;
}
return 1;
}
If you take the above C function and compile it into a shared library,
the ctypes
library makes it easy to access. The following shared
libraries have already been precompiled with the above function:
Ext/win32/libmandel.dll (Windows)
Ext/osx/libmandel.so (Macintosh OS-X)
Ext/linux/libmandel.so (Linux)
Try using ctypes to load the appropriate library depending on what operating system you’re using:
>>> import ctypes
>>> ext = ctypes.cdll.LoadLibrary("./win32/libmandel.dll")
>>>
Now, get a reference to the in_mandelbrot()
function and patch up its argument signatures:
>>> in_mandelbrot = ext.in_mandelbrot
>>> in_mandelbrot.argtypes = (ctypes.c_double, ctypes.c_double, ctypes.c_int)
>>> in_mandelbrot.restype = ctypes.c_int
>>>
Now, try calling the function for a few different values
>>> in_mandelbrot(0,0,500)
1
>>> in_mandelbrot(0.25,0.5,500)
1
>>> in_mandelbrot(2,2,500)
0
>>>
(c) A Performance Test
Take the mandel.py
program and copy it to a new program cmandel.py
. Modify the
program so that the in_mandelbrot()
function is loaded from a C library and used
instead of the Python implementation.
Run your new program and compare its performance to the pure-Python implementation. Make sure it produces the correct output.
More Information
Instead of using ctypes, Python also provides a low-level C programming API that allows extension modules to be directly integrated with this interpreter. More information can be found in the file practical-python/Optional/Extension.pdf.
Credits:
The PNG output created in this example is being produced by the PyPNG package (http://code.google.com/p/pypng).