2011-11-09 25 views
14

Mam kilka funkcji napisanych w C dla projektu gry. Funkcje te nazywane są całkiem często (około 2000-4000 razy na sekundę). Funkcje są napisane w C dla surowej prędkości.ctypes vs rozszerzenie C

Teraz najłatwiejszym sposobem włączenia tych funkcji do Pythona jest użycie ctypes. Alternatywą jest napisanie rozszerzenia C do Pythona wokół tych funkcji (co wymaga sporo dodatkowego wysiłku). Więc zastanawiałem się, nie wliczając początkowego ładowania biblioteki DLL, jak duże jest obciążenie związane z ctypes?


Używam Python 2.7 (standardowe wydanie CPython) i nie chcę używać zewnętrznej biblioteki, takiej jak Cython.

Wiem, że to pytanie zostało zadane wcześniej, ale nie widziałem wiele informacji na temat porównania wydajności dwóch opcji.

+0

Cóż, JIT PyPy może produkować całkiem niezły kod dla wywołań 'ctypes' od wydania lub dwóch. Możesz chcieć dać mu szansę. Nie publikuję tego jako odpowiedzi, ponieważ nie mam dostępu do twardych danych i nie jest jasne, czy zmiana tłumacza jest dla ciebie opcją. – delnan

+0

Spodziewam się, że koszty ogólne będą podobne. –

+0

@Delnan: To jest gra, którą zamierzam wysłać - również do Linuksa. Nie mogę poprosić moich użytkowników o zainstalowanie PyPy. – orlp

Odpowiedz

10

Porównałem wydajność rozszerzenia C w porównaniu z opakowaniem ctypes. W moim konkretnym teście różnica wynosiła około 250x. W bibliotece C było wiele wywołań, więc opakowanie ctypes również wykonywało kod Pythona. Czas działania biblioteki C był bardzo krótki, co dodatkowo zwiększało obciążenie kodu Pythona. Więc stosunek prawdopodobnie będzie inny dla ciebie, ale był znaczący w moim przypadku.

+5

A więc który z nich był wolniejszy 250x? – delnan

+1

@delnan: z jego odpowiedzi mogę odczytać opakowanie ctypes było wolniejsze. – orlp

6

Bezpośredni interfejs kodowany za pomocą C może być znacznie szybszy. Wąskie gardło jest interfejsem od Pythona do C i argumentów rozrządowych, a wyniki mogą na przykład obejmować kopiowanie ciągów lub konwersję list Pythona na/z tablic C. Jeśli masz pętlę, która wykonuje kilkaset takich połączeń, a niektóre dane nie muszą być osobno zestawiane dla każdego połączenia, wszystko co musisz zrobić, to przekodować pętlę w C i być może uda ci się znacznie zmniejszyć wąskie gardło . ctypes nie daje tej opcji: możesz tylko wywołać istniejące funkcje bezpośrednio.

Oczywiście wszystko zależy od tego, jakie funkcje wywołujesz i jakie dane przechodzisz. Możliwe, że nie można zmniejszyć kosztów ogólnych, w którym to przypadku nadal oczekiwałbym, że cpy będą wolniejsze, ale być może nie znacząco.

Najlepiej byłoby skompletować próbkę kodu napisanego w każdy sposób i porównać go. W przeciwnym razie istnieje zbyt wiele zmiennych, aby uzyskać ostateczną odpowiedź.

+0

Dane, o których mówimy, to maska ​​bitowa (dla kolizji). Mam implementację C gotową i jedyną dane przekazywane w kodzie Pythona to wartości logiczne, współrzędne i nowe klasy bitmaskowe Pythona (które zawierają tylko wskaźnik do samych danych, które znajdują się w kodzie C.) – orlp