Wydajność Pythona, C, C++ na przykładzie generowania miniatur grafik

Miniatury z dużych plików JPG możemy tworzyć za pomocą PIL, IMAGEMAGICK, czy EPEG/libjpeg. Dla biblioteki EPEG możemy też stworzyć Pythonone moduły za pomocą C/Python, czy BOOST/Python.

Parę dni temu bawiłem się różnymi bibliotekami do tworzenia miniatur z dużych plików JPG. EPEG to prosta biblioteka napisana w C, więc dość łatwo zrobić z niej moduł Pythona, a mając moduł Pythona można porównać różnice szybkości w działaniu czystego C od rozszerzenia C lub C++ dla języka skryptowego - Pythona :) Wspomniany test znajdziemy w Bibliotece CMS - Test tworzenia miniatur w PIL, Epeg i ImageMagick. Rozszerzenia w Pythonie możemy tworzyć w C używając API dostarczonego z Pythonem, lub też użyć biblioteki BOOST dla C++ posiadającą moduł umożliwiający proste tworzenie modułów Pythona.

Kod rozszerzeń C i C++/BOOST

Standardowe rozszerzenie Pythona napisane w C wyglądałoby tak:
#include <stdlib.h>
#include <unistd.h>
#include <Python.h>
#include <Epeg.h>

static PyObject *
epg_thumbnail(PyObject *self, PyObject *args)
{
	Epeg_Image * image;
	int ch, height, quality, width;
	char *input, *output;
	
	if (!PyArg_ParseTuple(args, "ssiii", &input, &output, &quality, &height, &width))
		return NULL;
	
	image = epeg_file_open(input);
	
	if (!image) {
		exit (0);
	}
	
	epeg_decode_size_set(image, width, height);
	epeg_quality_set    (image, quality);
	epeg_file_output_set(image, output);
	epeg_encode(image);
	epeg_close(image);

	
	Py_BuildValue("i", 1);
}

static PyMethodDef epg_methods[] = {
	{"thumbnail", (PyCFunction)epg_thumbnail, METH_VARARGS, "Funkcja epeg."},
	{NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC initepg() {
	Py_InitModule3("epg", epg_methods, "Miniatury z Epeg");
}
Kompilujemy poleceniem (-fPIC potrzebne na 64 bitowych systemach):
gcc -shared -I /usr/include/python2.5/ epg.c -o epg.so -fPIC `epeg-config --cflags --libs`

Rozszerzenie Pythona stworzone za pomocą BOOST wyglądałoby tak:
#include <boost/python.hpp>

#include <stdlib.h>
#include <unistd.h>
#include <Epeg.h>

int
thumbnail(char *input, char *output, int quality, int height, int width)
{
    Epeg_Image * image;
    int ch;

    image = epeg_file_open(input);

    if (!image) {
        exit (0);
    }

    epeg_decode_size_set(image, width, height);
    epeg_quality_set    (image, quality);
    epeg_file_output_set(image, output);
    epeg_encode(image);
    epeg_close(image);


    return 0;
}


BOOST_PYTHON_MODULE(bstepg)
{
    using namespace boost::python;
    def("thumbnail", thumbnail);
}
Kompilujemy poleceniem (-fPIC potrzebne na 64 bitowych systemach):
gcc -lboost_python -shared -I /usr/include/python2.5/ bstepg.cpp -o bstepg.so -fPIC `epeg-config --cflags --libs` -I/usr/include/boost

Test szybkości działania

Dla 18 dużych plików JPG (tapety) o rozmiarze 35MB przeprowadziłem test tak jak opisany w Bibliotece CMS osiągając wyniki (użyłem inny zestaw plików):
  • EPEG - 4,15s
  • PyEPEG C - 4,54s
  • PyEPEG BOOST - 4,58s
  • PIL - 11,61s
  • IMAGEMAGICK - 29,32s
  • IMAGEMAGICK -size - 10,9s (aktualizacja)
epeg, python, boost, imagemagick, pil
W przypadku stosowania biblioteki EPEG - najszybszej w tym zestawieniu - jako modułu Pythona tracimy jakieś 10% szybkości działania, co i tak jak widać jest znacznie szybsze w porównaniu do PIL, czy imagemagick. Porównując kod rozszerzenia napisany z wykorzystaniem API Pythona, do tego stworzonego z pomocą BOOST wyraźnie widać że BOOST jest mniej "złożone".
blog comments powered by Disqus

Kategorie

Strony