Avevamo già parlato di Cython, ovvero un ibrido fra C e Python, di fatto una specie di "estensione di Python" per rendere più efficiente il codice, con una sintassi appunto "ibrida". Tuttavia, questa complicazione può essere evitata e si possono "unire C e Python" in altro modo, lasciando ad ognuno la propria area di competenza.
Un esempio suddiviso in step spiega meglio questo concetto:
- si vuole creare una Heatmap in Python, quindi una visualizzazione grafica, su una griglia NxN, di una funzione trigonometrica che cambia nel tempo
- nessuno vieta di eseguire tutto tramite linguaggio Python, tuttavia, è ben nota l'enorme differenza di efficienza fra Python e C (vedi benchmark), quindi all'aumentare della complessità, ad esempio la dimensione di N, le prestazioni di Python ne risentono, in termini di tempo di esecuzione totale
- C invece consente un codice estremamente efficiente ma la grafica non può essere (facilmente) gestita tramite C
- soluzione:
- programma in C, che esegue tutte le operazioni matematiche, dove (specie all'aumentare di N) è richiesta efficienza computazionale
- stampa su file dei risultati (output.txt)
- file Python che prende in input il risultato generato dal programma in C e semplicemente ne rappresenta il grafico tramite la libreria Matplotlib
- per la massima versatilità (dover mettere mano solo al programma C) lo script Python NON viene creato a priori, ma generato automaticamente dallo stesso codice C! Inserire tutto tramite fptintf() non è semplicissimo, soprattutto vista l'identazione che Python richiede, tuttavia questo è molto comodo perché si possono inserire termini come N (dimensione matrice NxN) e il tempo t, come variabili! Ovvero cambiandone il valore a livello di dichiarazione variabili nel programma in C, il rispettivo programma Python generato dopo la compilazione ed esecuzione del programma C, avrà il valore aggiornato, anziché doverlo cambiare a mano
Per la compilazione del file C da terminale tramite GCC occorre il codice: gcc file.c -o file -lm
, con -lm dovuta alla presenza in questo caso della libreria <math.h>.
Riportiamo dunque tutto il codice C e successivamente degli screenshot della Heatmap che si ottiene avviando lo script Python che viene generato, per i tempi t=1, t=2, t=5.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){
register unsigned short i,j,t;
register unsigned short N=50;
register float w;
float V[N][N];
FILE *f1=fopen("output.txt","w");
t=1;
w=0.5+1.5*exp(-t);
for(j=0;j<N;j++){
for(i=0;i<N;i++){
V[i][j]=sin(t)*sin(t)*sin(w*i)*sin(w*j);
}
}
for(j=0;j<N;j++){
for(i=0;i<N;i++){
fprintf(f1,"%.2f ",V[i][j]);
}
fprintf(f1,"\n");
}
fclose(f1);
FILE *f2=fopen("grafico.py","w");
fprintf(f1,"import numpy as np\nfrom matplotlib import pyplot as plt\nN=%d\nwith open(\"output.txt\", \"r\") as f:\n\tcontent = f.read().strip()\n\tlines = content.split(\"\\n\")\n\tV = np.zeros((%d,%d))\n\tfor i, line in enumerate(lines):\n\t\tvalues = line.split()\n\t\tfor j, value in enumerate(values):\n\t\t\tV[i][j] = float(value)\ncolor=\'YlGnBu\'\nplt.imshow(V,color)\nplt.title(\"Heatmap al tempo t=%d\")\nplt.show()",N,N,N,t);
fclose(f2);
return 0;
}
Questo è solo un esempio semplice, ma rende l'idea. Avendo già visto un benchmark di prestazioni fra C e Python, in alcuni casi, molte operazioni da eseguire, Python può risultare anche 100 volte più lento rispetto a C! Quindi l'idea migliore è quella di far girare il codice "pesante" tramite C, avendo la massima efficienza e il risultato "farlo comunicare" tramite Python (ovvero come in questo esempio, scrivere la matrice su file e successivamente tramite Python acquisire la matrice da file, per poi creare la visualizzazione grafica).
Riportiamo quindi un semplice schemino per rendere più chiaro il concetto:
programma C -> stampa su file risultato -> file Python che acquisisce il risultato da file e crea il grafico (creato separatamente oppure generato dal programma C)
Un'alternativa per eseguire codice C tramite Python è tramite la libreria CFFI di Python.