Программисты знакомые с ctypes врядли найдут тут что-то интересное, новичков же прошу под кат.
Ctypes — механизм Python для импорта функций из внешних библиотек.
%timeit — magic-функция оболочки IPython, измеряющая время выполнения выражения на Python
Ctypes — это прекрасно! Давайте начнем с небольшого банального примера: суммирование чисел в определенном диапазоне.
Вот реализация этой функции на Python
def sumrange(arg): return sum(xrange(arg))
Отлично! Но что если мы попробуем суммировать действительно большой диапазон чисел, например от 0 до 10**8 (т.е. 100,000,000)
In [2]: %timeit sumrange(10**2) 1000000 loops, best of 3: 1.53 us per loop In [3]: %timeit sumrange(10**8) 1 loops, best of 3: 9.77 s per loop In [4]: %timeit sumrange(10**9) 1 loops, best of 3: 97.8 s per loop
Уже не так весело. Попробуем кое-что другое:
def sumrange2(arg): x = i = 0 while i < arg: x += i i += 1 return x
Что из этого получится?
In [10]: %timeit sumrange2(10**2) 100000 loops, best of 3: 10.5 us per loop In [11]: %timeit sumrange2(10**8) 1 loops, best of 3: 18.5 s per loop
Вот это да… Так еще хуже… В этот раз даже не буду пробовать 10**9.
Так как же нам ускорить выполнение? Только не предлагайте математические оптимизации… мы же в новом мире компьютеров! (в оригинале: don’t suggest math tricks… this is the the new world of computing!)
Да, я знаю, что сложность алгоритма — постоянная величина и не зависит о величины аргумента, n*(n+1)/2. Но статья посвящена не этому.
Как насчет ctypes?
#include <stdio.h> unsigned long long sumrange(unsigned long long arg) { unsigned long long i, x; x = 0; for (i = 0; i < arg; i++) { x = x + i; } return x; }
Сохраним с именем sumrange.c и скомпилируем (не будем использовать оптимизации для чистоты эксперимента):
$ gcc -shared -Wl,-install_name,sumrange.so -o sumrange.so -fPIC sumrange.c
Импортируем в Python то что получилось:
import ctypes sumrange_ctypes = ctypes.CDLL('./sumrange.so').sumrange sumrange_ctypes.restype = ctypes.c_ulonglong sumrange_ctypes.argtypes = ctypes.c_ulonglong,
И Оскар получает…
In [15]: %timeit sumrange_ctypes(10**2) 1000000 loops, best of 3: 1.28 us per loop In [16]: %timeit sumrange_ctypes(10**8) 1 loops, best of 3: 381 ms per loop In [17]: %timeit sumrange_ctypes(10**9) 1 loops, best of 3: 3.79 s per loop In [18]: %timeit sumrange_ctypes(10**10) 1 loops, best of 3: 37.8 s per loop
Итоговая сводка:
10**2 | 10**8 | 10**9 | 10**10 | |
---|---|---|---|---|
Чистый Python, способ №1 | 1.53 мкс | 9.77 с | 97.8 с | — |
Чистый Python, способ №2 | 10.5 мкс | 18.5 с | — | — |
ctypes | 1.28 мкс | 381 мс | 3.79 с | 37.8 с |
Адский прирост производительности!
Для Node.js хакеров, есть эквивалент ctypes — FFI (Foreign Function Interface): github.com/rbranson/node-ffi
ссылка на оригинал статьи http://habrahabr.ru/post/157537/
Добавить комментарий