Il semble que le projet LLVM ait publié un FFI appelé Dragon FFI. Blog montre un exemple d'appel du langage C à partir de Python.
À propos, FFI est une abréviation de Foreign Function Interface, qui est un mécanisme qui vous permet d'utiliser des fonctions définies dans un langage de programmation dans un autre. Par exemple, Rust, qui a été créé pour remplacer C, a implémenté FFI pour appeler C.
J'ai joué avec pydffi, le Python Wrapper de DragonFFI.
Pour Python, j'ai utilisé "Python 3.6.3 :: Anaconda, Inc." installé par pyenv. La bibliothèque était facile à installer avec pip.
pip install pydffi
Je ne voulais vraiment rien faire, j'ai donc implémenté une fonction de séquence de Fibonacci en Python et C. L'idée est qu'une fonction écrite en C devrait avoir une vitesse d'exécution rapide, il serait donc intéressant de voir la valeur numérique.
def f(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return f(n-1)+f(n-2)
print(f(30))
pydffi
Définissez une fonction f comme celle-ci.
int f(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return f(n-1) + f(n-2);
}
}
Appelez la fonction f définie en C depuis Python. Avec pydffi, c'était très simple à écrire!
import pydffi
with open("cfunc/fibonacci_opt.c") as f:
c_src = "".join(f.readlines())
F = pydffi.FFI()
CU = F.compile(c_src)
print(int(CU.funcs.f(30)))
Exécuté à N = 30. C'est une fonction qui n'a pas du tout été optimisée, il est donc naturel que le langage C soit plus rapide.
Fonctions Python | Fonction C(pydffi) |
---|---|
0.3381[sec] | 0.0496[sec] |
Au fait, si vous optimisez Python en prenant des notes, cela ressemble à ceci. (vite!) L'algorithme est important.
Python(Note) |
---|
0.00005[sec] |
memo = [0] * 1000
def f(n):
if n == 0:
return 0
elif n == 1:
return 1
if memo[n]:
return memo[n]
m = f(n-1)+f(n-2)
memo[n] = m
return m
print(f(30))
Je voulais un autre échantillon, j'ai donc implémenté la multiplication matricielle, appelée matmul. Cette fois, numpy est également une cible de comparaison.
A = [random.random() for _ in range(N) for _ in range(N)]
B = [random.random() for _ in range(N) for _ in range(N)]
C = [0.0 for _ in range(N) for _ in range(N)]
for i in range(N):
for j in range(N):
for k in range(N):
C[i * N + j] += A[i * N + k] * B[k * N + j]
pydffi
void matmul(double *A, double *B, double *C, int N) {
int i, j, k;
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
for (k = 0; k < N; k++) {
C[i * N + j] += A[i * N + k] * B[k * N + j];
}
}
}
}
# read c source
with open("cfunc/matmul.c") as f:
c_src = "".join(f.readlines())
# initialize
FFI = pydffi.FFI()
CU = FFI.compile(c_src)
# create array objects & set values
arr_A = pydffi.CArrayObj(FFI.arrayType(FFI.DoubleTy, N*N))
arr_B = pydffi.CArrayObj(FFI.arrayType(FFI.DoubleTy, N*N))
arr_C = pydffi.CArrayObj(FFI.arrayType(FFI.DoubleTy, N*N))
for i in range(N*N):
arr_A.set(i, A[i])
arr_B.set(i, B[i])
arr_C.set(i, 0.0)
# execute c matmul
start = time.time()
CU.funcs.matmul(arr_A, arr_B, arr_C, N)
print("C(FFI):{:.5f}[sec]".format(time.time() - start))
numpy
np_A = np.array(A).reshape(N, N)
np_B = np.array(B).reshape(N, N)
np_C = np.matmul(np_A, np_B)
N=256 Après tout, la fonction C est rapide. Et numpy est le plus rapide, comme prévu. Eh bien, C n'est qu'une triple boucle, il y a donc de la place pour plus d'optimisation. (⇒ Pour ceux qui sont intéressés par l'optimisation de matmul, ici sera utile)
Fonctions Python | Fonction C(pydffi) | numpy |
---|---|---|
7.1067[sec] | 0.0329[sec] | 0.0281[sec] |
N=1024
Fonctions Python | Fonction C(pydffi) | numpy |
---|---|---|
Aucune mesure | 7.4422[sec] | 0.0769[sec] |
Recommended Posts