niedziela, grudnia 25, 2005

Początek ery Pyreksa?

SWIG przeszedł do historii z chwilą, w której stwierdziłem, że kod wygenerowany na jednym komputerze nie chce działać na innym. I to wszystko, co mam do powiedzenia na temat SWIGa.

Poszukiwania innych narzędzi skończyły się na Pyreksie. Nie jest to narzędzie tego samego typu, co SWIG - jest to raczej rodzaj języka skryptowego, w którym można pisać moduły dla Pythona. W Pyreksie stosuje się kilka sztuczek, dzięki którym takie moduły działają potem znacznie szybciej, niż gdyby były napisane w Pythonie.

Jedną z podstawowych sztuczek jest stosowanie typów danych znanych z C. Dzięki temu można (podobno, nie sprawdzałem tego jeszcze) uzyskać znaczne przyspieszenie kodu. No myślę - jeśli nie trzeba za każdym razem sprawdzać, jakie są typy danych, które próbuje do siebie dodać programista...

Ale nie na tym polega urok Pyreksa. Jak dla mnie największe znaczenie mają przede wszystkim dwie jego cechy:

1) Mogę z łatwością używać funkcji napisanych w C. Jedyne, co muszę w tym celu zrobić, to napisać jedną, prostą linię kodu w Pyreksie, która "importuje" taką funkcję napisaną w C, a następnie - jeśli chcę tę funkcję wywoływać z poziomu Pythona, napisać jeszcze funkcję-wrapper w Pythonie. To znaczy w języku Pyreksa, ale różnice pomiędzy nimi są doprawdy niewielkie.

2) Pyrex jest modułem dla Pythona i działa po prostu pod Pythonem. Dzięki temu działa wszędzie tam, gdzie jest Python.

Chciałbym tylko jeszcze zrobić jeden test: zakodować ten sam algorytm w Pythonie, w Pyreksie (korzystając z jego możliwości), oraz w czystym C (i "podpiąć" to pod Pythona przy pomocy Pyreksa) - i sprawdzić szybkość wykonywania tych implementacji. Tylko ciągle jeszcze nie wiem, jaki algorytm wybrać do testów... (No i kiedy znaleźć na to czas?)

czwartek, września 22, 2005

C, SWIG, Python

Ostatnie dni upłynęły mi na tłumaczeniu kodu z Pythona na C oraz na poznawaniu nowych narzędzi służących do łączenia kodu napisanego w tych językach.

W większości udało mi się już zrobić to, co chciałem, w czystym C. Problem "podpięcia" tego pod Pythona rozwiązałem przy pomocy Swiga, który okazał się być zdecydowanie przyjemniejszy, niż API Pythona dla rozszerzeń w C/C++.

Cały problem mógłbym przedstawić następująco: można wykorzystać API Pythona dla rozszerzeń C/C++ i pisać w taki sposób, że cała konwersja pomiędzy typami danych stosowanymi w Pythonie i w C będzie pisana w C. W takim przypadku trzeba jednak używać tego niezbyt wygodnego API.

Korzystając ze Swiga sytuacja zostaje odwrócona - w Pythonie można łatwo tworzyć typy danych stosowane później przez funkcje napisane w C. Konwersja z tych typów na typy stosowane w Pythonie odbywa się jednak w czystym Pythonie, czyli jest to zdecydowanie łatwiej napisać, niż w C.

Użycie Swiga nie wyklucza oczywiście zastosowania distutils. Korzystanie ze Swiga sprowadza się do wygenerowania przez ten program jednego pliku w C, takiego "wrappera" dla właściwego kodu w C. Kod ten trzeba po prostu skompilować (czyli trzeba distutils powiedzieć, że ma skompilować kod z tego pliku) - i tyle.

Napotkałem jednak spore problemy przy korzystaniu z GLiba pod Swigiem. Ostatecznie zdecydowałem się nie używać w interfejsie tworzonego rozszerzenia żadnych danych z GLiba, a jedynie użyć tych typów danych z GLiba wewnętrznie w module. W ten sposób cały interfejs sprowadził się do czystego C, zaś moduł wykorzystuje listy i tablice z GLiba w sposób "niewidoczny" dla Swiga. Trzeba oczywiście pamiętać o odpowiednim zlinkowaniu skompilowanego modułu z tą biblioteką.

Tylko jak by to działało pod Windows? Tam użycie dzielonych bibliotek chyba nie jest tak powszechne, jak pod GNU/Linuksem... Kiedyś będę się musiał o tym przekonać. (Zresztą - póki co i tak nikogo nie obchodzi to, nad czym pracuję, więc mogę się spokojnie ograniczyć do systemów z rodziny GNU/Linuksa.)

W najbliższych dniach wykonam jeszcze testy na prędkość tych modułów napisanych w C (tłumaczyłem kod z Pythona i chcę zobaczyć, ile zyskałem), po czym wreszcie uruchomię kolejny eksperyment. Już nie mogę się doczekać!

A potem czeka mnie wreszcie powrót do czystego Pythona. Cóż za ulga po tworzeniu kodu w C, gdzie musiałem *ręcznie* utworzyć każdy obiekt w pamięci i zwolnić później tę pamięć, wyłowić w programie parę wycieków pamięci... Ech - nie ma to jak Python.

czwartek, września 15, 2005

Powrót do C

Ostatnio zostałem "zmuszony" do napisania kodu w czystym C. Mam działający kod w Pythonie, ale jego szybkość pozostawia naprawdę wiele do życzenia. Zdecydowałem się więc na przetłumaczenie tego kodu z Pythona na C.

Dlaczego C, a nie w C++? Z kilku powodów:

1) Piszę moduły dla Pythona. Całego Pythona skompilowałem używając kompilatora C, a nie C++ - więc po prostu łatwiej mi jest teraz pisać moduły w czystym C (buduję je przy pomocy distutils). Całe zbudowanie modułu sprowadza się do wydania jednego polecenia - "python setup.py build".

2) Zdecydowanie lepiej znam C niż C++. A moduły dla Pythona można również pisać w C++, lecz trzeba przestrzegać pewnych reguł... Nie chce mi się wnikać w takie szczegóły - uważam, że mniej się namęczę, jeśli wszystko zrobię w czystym C. I tak nie muszę używać programowania obiektowego, więc w tym przypadku wydaje mi się, że C ma pewną przewagę nad C++.

Przetłumaczenie działającego kodu z Pythona na C nie jest aż takie trudne. Jednakże wczoraj napotkałem na problem, którego nie byłem w stanie rozwiązać przy pomocy tablic w C - musiałem użyć list. Listy są "zwykłym" typem w Pythonie, lecz nie w C.

Miałem do wyboru : albo sam napiszę jakąś prostą bibliotekę do obsługi list, albo nie będę wynajdywał koła i skorzystam z tego, co przede mną zrobili już inni.

Zazwyczaj perspektywa samodzielnego napisania takiej biblioteki byłaby dla mnie - zapalonego kodera - niezwykle kusząca. Mógłbym zrobić to w sposób naśladujący API list z Pythona - i zapewne tłumaczenie kodu byłoby znacznie prostsze. Poza tym miałbym własny kod, wiedziałbym, co w nim mam, mógłbym go bez większego problemu dołączyć do każdego modułu, nad jakim pracuję.

Tylko że mnie się spieszy. Chciałbym jak najszybciej zrobić to, co mam do zrobienia i uruchomić kolejny eksperyment. Zdecydowałem się więc na wykorzystanie GLib.

Będę musiał się wprawdzie nauczyć API, które wymyślił ktoś inny - ale myślę, że w perspektywie to mi się opłaci. Bo skąd mam wiedzieć, czy np. jutro (albo za miesiąc) nie okaże się, że oprócz list potrzebuję czegoś jeszcze? Czegoś, czego napisanie znowu zajęłoby mi czas (i musiałbym się skupić na rozwiązaniu jakiegoś niskopoziomowego zadania zamiast na właściwym celu mojej pracy)? A GLib jest bardzo bogatą biblioteką (porównałbym ją do STL w C++) - i jest duża szansa na to, że będzie w niej już to, co mi będzie potrzebne za jakiś czas.

(Mała dygresja. Mam oczywiście nadzieję, że po napisaniu tego kodu w C będę mógł powrócić do mojego ulubionego Pythona i nie zajmować się dłużej programowaniem niskopoziomowym. Oczywiście oprócz ulepszania już istniejącego kodu. Ale nadzieje nadziejami, a życie życiem.)

Użycie GLib będzie miało też inną, wielką zaletę. Otóż użyję biblioteki przetestowanej. Gdybym wykorzystał własną, musiałbym ją przetestować. Ponieważ zaś nie mam czasu na pisanie testów z prawdziwego zdarzenia, w praktyce sprowadziłoby się to zapewne do testowania jej na "żywym" obiekcie - czyli na moim programie. Korzystając z GLib mam pewność, że używam biblioteki przetestowanej i działającej - a błędów powinienem szukać raczej we własnym kodzie (którego teraz będzie zdecydowanie mniej :D).

Z przymrużeniem oka. Mam jednak pewne obawy... Tak samo, jak wówczas, kiedy poznałem Pythona i zrozumiałem, że jego wykorzystanie może naprawdę znacznie skrócić czas tworzenia oprogramowania. W ciągu zaledwie miesiąca czasu porzuciłem Javę - dla której kilka miesięcy wcześniej zrezygnowałem z używania mojego ukochanego C (do dzisiaj bardzo lubię ten język!) - na rzecz Pythona właśnie. Python ma wiele zalet (development jest naprawdę znacznie szybszy, niż w jakimkolwiek innym znanym mi języku), ale jest potwornie wolny. A mnie jest potrzebna prędkość (ostatni eksperyment trwał ponad miesiąc czasu!). Czyżby więc istniła możliwość, że porzuciłbym Pythona na rzecz C?

E tam... Nie ma się czego bać. Python świetnie nadaje się do "klejenia" różnych fragmentów kodu, napisanych czasami w różnych językach. A tam, gdzie Python jest zbyt wolny, pisze się dodatkowe moduły w C. I to właśnie teraz robię. Cóż - tutaj akurat to ja jestem pionierem.