2011-02-10 6 views
6

Ho uno script python e un programma C (ho scritto entrambi, quindi ho il sorgente). Ho bisogno di passare grandi quantità di dati dallo script Python che chiamano molte volte il programma C. In questo momento lascio che l'utente scelga di passarli con un file ascii o un file binario, ma entrambi sono piuttosto lenti e inutili (voglio dire, i file sono utili se si desidera archiviare i dati, ma io cancello questi file alla fine di il copione). os.system non funziona, gli argomenti sono troppi. (Anche il programma C usa i file per restituire dati a Python, ma questo è molto meno dati)Passaggio di molti dati dal programma Python al programma C

Mi chiedo che cosa posso usare per rendere questo scambio veloce. Scrivere i file su un disco ram? Se è così, come posso fare questo?

Ho sentito è possibile chiamare le funzioni da dll utilizzando i tipi, ma non so come compilare il mio programma come dll (io uso wxdevC++ su win 7 64). Oppure avvolgilo, ma ancora non so se può funzionare e se è efficiente ..

Qualcuno può dirmi come posso fare questo?

(i dati sono vertici di una mesh 3D)

EDIT: Forse più informazioni possono aiutare. Sto eseguendo lo script python all'interno di un altro programma (blender (open source)), e viene chiamato più volte (di solito più di 500 volte) perché è all'interno di un ciclo. Lo script invia informazioni sul vertice (1 int index e 3 float coords) al programma, e il programma dovrebbe restituire molti vertici (solo indice int, perché posso trovare i vertici corrispondenti con python). Quindi questo non è interattivo, è più simile a una funzione (ma è scritto in C). Il programma script + C (che sono componenti aggiuntivi di Blender) che sto scrivendo dovrebbe essere multipiattaforma perché verrà ridistribuito (darò la fonte e programmi compilati). Forse questa nota può aiutare: il programma è in realtà scritto in C, e da python posso conoscere l'indirizzo in memoria della struttura che contiene i dati dei vertici. Se solo so come farlo, dovrebbe essere meglio passare al programma C solo un indirizzo, e da lì trovare tutti gli altri vertici (sono memorizzati nella lista). Ma per quanto ne so, non posso accedere allo spazio di memoria di un altro programma, e non so se chiamare il programma con pipe o qualsiasi altra cosa inizializzi un nuovo thread o venga eseguito all'interno dello script (che in realtà viene eseguito sotto il filo Blender) Ps: here the source e qui (3) dovrebbe essere la definizione struct

(3): frullatore/source/frullatore/makesdna/DNA_meshdata_types.h

risposta

6

I tubi sono la soluzione più ovvia; se il tuo programma c accetta input da stdin, puoi usare Popen. Questo non crea una "discussione" come dici tu nella tua modifica; crea un completamente nuovo processo con la memoria separata:

from subprocess import Popen, PIPE 

input = "some input" 
cproc = Popen("c_prog", stdin=PIPE, stdout=PIPE) 
out, err = cproc.communicate(input) 

Ecco un esempio più dettagliato. In primo luogo, un semplice programma c che riecheggia stdin:

#include<stdio.h> 
#include<stdlib.h> 
#define BUFMAX 100 

int main() { 
    char buffer[BUFMAX + 1]; 
    char *bp = buffer; 
    int c; 
    FILE *in; 
    while (EOF != (c = fgetc(stdin)) && (bp - buffer) < BUFMAX) { 
     *bp++ = c; 
    } 
    *bp = 0; // Null-terminate the string 
    printf("%s", buffer); 
} 

Poi un programma Python che i tubi di ingresso (da argv in questo caso) a quanto sopra:

from subprocess import Popen, PIPE 
from sys import argv 

input = ' '.join(argv[1:]) 
if not input: input = "no arguments given" 
cproc = Popen("./c_prog", stdin=PIPE, stdout=PIPE) 
out, err = cproc.communicate(input) 
print "output:", out 
print "errors:", err 

Se non si prevede di utilizzare il programma c senza il frontend python, tuttavia, potrebbe essere meglio inlining la funzione ac, magari usando instant.

from instant import inline 
c_code = """ 
    [ ... some c code ... ] //see the below page for a more complete example. 
""" 
c_func = inline(c_code) 

Come Joe fa notare, si potrebbe anche scrivere un modulo python in c: Extending Python with C or C++

Questa risposta discute altri modi di combinare C e Python: How do I connect a Python and a C program?

EDIT: Sulla base della sua modifica, sembra proprio che dovresti creare un'estensione cpthon. Se vuoi un codice di esempio, fammi sapere; ma una spiegazione completa farebbe una risposta irragionevolmente lunga. Vedi il link sopra (Extending Python ...) per tutto ciò che devi sapere.

+0

ho scritto il programma C, posso cambiare come voglio. Quindi comunicare qualcosa con le pipe è come scrivere nello stdin? –

+0

Se ho capito bene, si. Pubblicherò un esempio per ogni evenienza. – senderle

+0

Ok, ho capito il tuo codice. Sfortunatamente avrò ridistribuito il codice, quindi preferisco usare solo le librerie standard (ho visto che l'istante è una libreria esterna). Proverò con le pipe. E ti disturbo un po 'di più: pensi che fare una libreria condivisa e chiamarla con i ctype funzionerebbe altrettanto? Btw davvero interessante la cosa in linea! –

4

Se il sistema operativo supporta, named pipes sono un calo nella sostituzione dei file.

+0

named pipe sono ammessi solo in UNIX (così dice la documentazione) –

1

Ecco un'idea leggermente diversa dalle altre: Scrivi il tuo programma C come un modulo Python. Here sono tutte le informazioni necessarie per farlo. È quindi possibile passare grandi buffer avanti e indietro tra il codice Python e il codice C.

0

Non sono mai stato soddisfatto delle risposte di collegamento tra Python e C, quindi ho scritto una risposta dopo una buona dose di ricerca e riflessione.

test.c

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    FILE *fp; 
    char path[1035]; 

    fp = popen("python3 output2.py", "r"); // Open the command for reading. 
    if (fp == NULL) { 
     printf("Failed to run command\n"); 
     exit(1); 
    } 

    while (fgets(path, sizeof(path), fp) != NULL) 
     printf("C received %s", path); // Read the output. 

    pclose(fp); // close 

    return 0; 
} 

output2.py

import time 
import os, sys 

i = 0 
while True : 
    print("%d" %(i), flush=True) 
    time.sleep(1) 
    i = i + 1