Es scheint, dass das LLVM-Projekt einen FFI namens Dragon FFI veröffentlicht hat. Blog zeigt ein Beispiel für das Aufrufen der C-Sprache aus Python.
FFI ist übrigens eine Abkürzung für Foreign Function Interface, ein Mechanismus, mit dem Sie Funktionen verwenden können, die in einer Programmiersprache in einer anderen definiert sind. Beispielsweise implementiert Rust, das als Ersatz für C erstellt wurde, FFI, um C aufzurufen.
Ich habe mit Pydffi gespielt, DragonFFIs Python Wrapper.
Für Python habe ich "Python 3.6.3 :: Anaconda, Inc." verwendet, das von pyenv installiert wurde. Die Bibliothek war einfach mit pip zu installieren.
pip install pydffi
Ich wollte eigentlich nichts tun, also habe ich eine Fibonacci-Sequenzfunktion in Python und C implementiert. Die Idee ist, dass eine in C geschriebene Funktion eine schnelle Ausführungsgeschwindigkeit haben sollte, daher wäre es interessant, den numerischen Wert zu sehen.
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
Definieren Sie eine solche Funktion f.
int f(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return f(n-1) + f(n-2);
}
}
Rufen Sie die in C definierte Funktion f in Python auf. Mit pydffi war es sehr einfach zu schreiben!
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)))
Wird bei N = 30 ausgeführt. Es ist eine Funktion, die überhaupt nicht optimiert wurde, daher ist es natürlich, dass die C-Sprache schneller ist.
Python-Funktionen | C-Funktion(pydffi) |
---|---|
0.3381[sec] | 0.0496[sec] |
Übrigens, wenn Sie Python durch Notizen optimieren, sieht es so aus. (schnell!) Der Algorithmus ist wichtig.
Python(Memo) |
---|
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))
Ich wollte ein anderes Beispiel, also implementierte ich die Matrixmultiplikation, das sogenannte Matmul. Diesmal ist Numpy auch ein Vergleichsziel.
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 Immerhin ist die C-Funktion schnell. Und Numpy ist erwartungsgemäß am schnellsten. Nun, C ist nur eine Dreifachschleife, also gibt es Raum für mehr Optimierung. (⇒ Für diejenigen, die an der Optimierung von matmul interessiert sind, ist hier hilfreich.)
Python-Funktionen | C-Funktion(pydffi) | numpy |
---|---|---|
7.1067[sec] | 0.0329[sec] | 0.0281[sec] |
N=1024
Python-Funktionen | C-Funktion(pydffi) | numpy |
---|---|---|
Keine Messung | 7.4422[sec] | 0.0769[sec] |
Recommended Posts